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 72a7e7c0..bd4dc10b 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,"iframeLibraryLoaded",!1),_defineProperty(this,"selectedLibraryVideo",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(/]*src=["']([^"']+)["'][^>]*>/i);return iframeMatch?this.parseEmbedUrl(iframeMatch[1]):input.startsWith("http://")||input.startsWith("https://")?this.parseVideoUrl(input):null}parseVideoUrl(url){try{const urlObj=new URL(url),baseUrl="".concat(urlObj.protocol,"//").concat(urlObj.host);if("/view"===urlObj.pathname&&urlObj.searchParams.has("m"))return{baseUrl:baseUrl,videoId:urlObj.searchParams.get("m"),isEmbed:!1};if("/embed"===urlObj.pathname&&urlObj.searchParams.has("m")){const tParam=urlObj.searchParams.get("t"),widthParam=urlObj.searchParams.get("width"),heightParam=urlObj.searchParams.get("height");return{baseUrl:baseUrl,videoId:urlObj.searchParams.get("m"),isEmbed:!0,showTitle:"1"===urlObj.searchParams.get("showTitle"),linkTitle:"1"===urlObj.searchParams.get("linkTitle"),showRelated:"1"===urlObj.searchParams.get("showRelated"),showUserAvatar:"1"===urlObj.searchParams.get("showUserAvatar"),width:widthParam?parseInt(widthParam):null,height:heightParam?parseInt(heightParam):null,startAt:tParam?this.secondsToTimeString(parseInt(tParam)):null}}return urlObj.pathname.includes("/filter/mediacms/launch.php")&&urlObj.searchParams.has("token")?{baseUrl:baseUrl,videoId:urlObj.searchParams.get("token"),rawUrl:url,isLtiLaunch:!0}:{baseUrl:baseUrl,rawUrl:url,isGeneric:!0}}catch(e){return null}}parseEmbedUrl(url){return this.parseVideoUrl(url)}secondsToTimeString(seconds){const mins=Math.floor(seconds/60),secs=seconds%60;return"".concat(mins,":").concat(secs.toString().padStart(2,"0"))}timeStringToSeconds(timeStr){if(!timeStr||!timeStr.trim())return null;if((timeStr=timeStr.trim()).includes(":")){const parts=timeStr.split(":");return 60*(parseInt(parts[0])||0)+(parseInt(parts[1])||0)}const secs=parseInt(timeStr);return isNaN(secs)?null:secs}parseWidthHeight(value){if(!value)return null;const trimmed=value.trim();if("100%"===trimmed)return"100%";const parsed=parseInt(trimmed);return isNaN(parsed)?null:parsed}buildEmbedUrl(parsed,options){if(parsed.isGeneric||parsed.isLtiLaunch)return parsed.rawUrl;const url=new URL("".concat(parsed.baseUrl,"/embed"));if(url.searchParams.set("m",parsed.videoId),url.searchParams.set("showTitle",options.showTitle?"1":"0"),url.searchParams.set("showRelated",options.showRelated?"1":"0"),url.searchParams.set("showUserAvatar",options.showUserAvatar?"1":"0"),url.searchParams.set("linkTitle",options.linkTitle?"1":"0"),!options.responsive&&options.width&&"100%"!==options.width&&url.searchParams.set("width",options.width.toString()),!options.responsive&&options.height&&"100%"!==options.height&&url.searchParams.set("height",options.height.toString()),options.startAtEnabled&&options.startAt){const seconds=this.timeStringToSeconds(options.startAt);null!==seconds&&seconds>0&&url.searchParams.set("t",seconds.toString())}return url.toString()}async getTemplateContext(){var _this=this;let data=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const editorData=(0,_options.getData)(this.editor),autoConvertOptions=(null==editorData?void 0:editorData.autoConvertOptions)||{},getDefault=function(key){let fallback=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return _this.isUpdating&&void 0!==data[key]?data[key]:void 0!==autoConvertOptions[key]?autoConvertOptions[key]:fallback};let isResponsive;return isResponsive=this.isUpdating&&(data.width||data.height)?"100%"===data.width||"100%"===data.height:!1!==data.responsive,{elementid:this.editor.getElement().id,isupdating:this.isUpdating,url:data.url||"",showTitle:getDefault("showTitle"),linkTitle:getDefault("linkTitle"),showRelated:getDefault("showRelated"),showUserAvatar:getDefault("showUserAvatar"),responsive:isResponsive,textLinkOnly:data.textLinkOnly||!1,startAtEnabled:data.startAtEnabled||!1,startAt:data.startAt||"0:00",width:data.width||"",height:data.height||"",is16_9:!data.aspectRatio||"16:9"===data.aspectRatio,is4_3:"4:3"===data.aspectRatio,is1_1:"1:1"===data.aspectRatio,isCustom:"custom"===data.aspectRatio}}async displayDialogue(){this.selectedIframe=this.getSelectedIframe();const data=this.getCurrentIframeData();this.isUpdating=null!==data,this.iframeLibraryLoaded=!1,this.currentModal=await _iframemodal.default.create({title:(0,_str.getString)("iframemodaltitle",_common.component),templateContext:await this.getTemplateContext(data||{})}),await this.registerEventListeners(this.currentModal)}getSelectedIframe(){const node=this.editor.selection.getNode();if("a"===node.nodeName.toLowerCase()&&"true"===node.getAttribute("data-mediacms-textlink"))return node;if("iframe"===node.nodeName.toLowerCase())return node;const iframe=node.querySelector("iframe");if(iframe)return iframe;const wrapper=node.closest(".tiny-mediacms-iframe-wrapper")||node.closest(".tiny-iframe-responsive");if(wrapper)return wrapper.querySelector("iframe");const textLink=node.closest('a[data-mediacms-textlink="true"]');return textLink||null}getCurrentIframeData(){var _parsed$showTitle2,_parsed$linkTitle2,_parsed$showRelated2,_parsed$showUserAvata2;if(!this.selectedIframe)return null;if("a"===this.selectedIframe.nodeName.toLowerCase()&&"true"===this.selectedIframe.getAttribute("data-mediacms-textlink")){var _parsed$showTitle,_parsed$linkTitle,_parsed$showRelated,_parsed$showUserAvata;const href=this.selectedIframe.getAttribute("href"),parsed=this.parseInput(href);return{url:href,width:(null==parsed?void 0:parsed.width)||560,height:(null==parsed?void 0:parsed.height)||315,showTitle:null===(_parsed$showTitle=null==parsed?void 0:parsed.showTitle)||void 0===_parsed$showTitle||_parsed$showTitle,linkTitle:null===(_parsed$linkTitle=null==parsed?void 0:parsed.linkTitle)||void 0===_parsed$linkTitle||_parsed$linkTitle,showRelated:null===(_parsed$showRelated=null==parsed?void 0:parsed.showRelated)||void 0===_parsed$showRelated||_parsed$showRelated,showUserAvatar:null===(_parsed$showUserAvata=null==parsed?void 0:parsed.showUserAvatar)||void 0===_parsed$showUserAvata||_parsed$showUserAvata,responsive:!0,textLinkOnly:!0,startAtEnabled:null!==(null==parsed?void 0:parsed.startAt),startAt:(null==parsed?void 0:parsed.startAt)||"0:00"}}const src=this.selectedIframe.getAttribute("src"),parsed=this.parseInput(src);let width=(null==parsed?void 0:parsed.width)||this.selectedIframe.getAttribute("width")||null,height=(null==parsed?void 0:parsed.height)||this.selectedIframe.getAttribute("height")||null;const isResponsive=(this.selectedIframe.getAttribute("style")||"").includes("aspect-ratio")||("100%"===width||"100%"===height);return isResponsive?(width="100%",height="100%"):(width=width?parseInt(width):null,height=height?parseInt(height):null),{url:src,width:width,height:height,showTitle:null===(_parsed$showTitle2=null==parsed?void 0:parsed.showTitle)||void 0===_parsed$showTitle2||_parsed$showTitle2,linkTitle:null===(_parsed$linkTitle2=null==parsed?void 0:parsed.linkTitle)||void 0===_parsed$linkTitle2||_parsed$linkTitle2,showRelated:null===(_parsed$showRelated2=null==parsed?void 0:parsed.showRelated)||void 0===_parsed$showRelated2||_parsed$showRelated2,showUserAvatar:null===(_parsed$showUserAvata2=null==parsed?void 0:parsed.showUserAvatar)||void 0===_parsed$showUserAvata2||_parsed$showUserAvata2,responsive:isResponsive,startAtEnabled:null!==(null==parsed?void 0:parsed.startAt),startAt:(null==parsed?void 0:parsed.startAt)||"0:00"}}getFormValues(root){const form=root.querySelector(_selectors.default.IFRAME.elements.form);return{url:form.querySelector(_selectors.default.IFRAME.elements.url).value.trim(),showTitle:form.querySelector(_selectors.default.IFRAME.elements.showTitle).checked,linkTitle:form.querySelector(_selectors.default.IFRAME.elements.linkTitle).checked,showRelated:form.querySelector(_selectors.default.IFRAME.elements.showRelated).checked,showUserAvatar:form.querySelector(_selectors.default.IFRAME.elements.showUserAvatar).checked,responsive:form.querySelector(_selectors.default.IFRAME.elements.responsive).checked,textLinkOnly:form.querySelector(_selectors.default.IFRAME.elements.textLinkOnly).checked,startAtEnabled:form.querySelector(_selectors.default.IFRAME.elements.startAtEnabled).checked,startAt:form.querySelector(_selectors.default.IFRAME.elements.startAt).value.trim(),aspectRatio:form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).value,width:this.parseWidthHeight(form.querySelector(_selectors.default.IFRAME.elements.width).value),height:this.parseWidthHeight(form.querySelector(_selectors.default.IFRAME.elements.height).value)}}async generateIframeHtml(values){const parsed=this.parseInput(values.url);if(!parsed)return"";if(values.textLinkOnly){let viewUrl;viewUrl=parsed.isGeneric||parsed.isLtiLaunch?parsed.rawUrl:"".concat(parsed.baseUrl,"/view?m=").concat(parsed.videoId);const linkText=(str=>{const div=document.createElement("div");return div.textContent=str,div.innerHTML})(viewUrl),hrefUrl=viewUrl.replace(/"/g,""");return'

').concat(linkText,"

")}const embedUrl=this.buildEmbedUrl(parsed,values),aspectRatioCalcs={"16:9":"16 / 9","4:3":"4 / 3","1:1":"1 / 1",custom:"".concat(values.width," / ").concat(values.height)},context={src:embedUrl,width:values.width,height:values.height,responsive:values.responsive,aspectRatioCalc:aspectRatioCalcs[values.aspectRatio]||"16 / 9",aspectRatioValue:aspectRatioCalcs[values.aspectRatio]||"16 / 9"},{html:html}=await _templates.default.renderForPromise("tiny_mediacms/iframe_embed_output",context);return html}async updatePreview(root){let updateUrlField=arguments.length>1&&void 0!==arguments[1]&&arguments[1];const values=this.getFormValues(root),previewContainer=root.querySelector(_selectors.default.IFRAME.elements.preview),urlWarning=root.querySelector(_selectors.default.IFRAME.elements.urlWarning);if(!values.url)return previewContainer.innerHTML='Enter a video URL to see preview',void urlWarning.classList.add("d-none");const parsed=this.parseInput(values.url);if(!parsed)return previewContainer.innerHTML='Invalid URL format',void urlWarning.classList.remove("d-none");urlWarning.classList.add("d-none");const embedUrl=this.buildEmbedUrl(parsed,values);if(updateUrlField&&!parsed.isGeneric){root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.url).value=embedUrl}if(values.textLinkOnly){let viewUrl;viewUrl=parsed.isGeneric||parsed.isLtiLaunch?parsed.rawUrl:"".concat(parsed.baseUrl,"/view?m=").concat(parsed.videoId);const linkText=(str=>{const div=document.createElement("div");return div.textContent=str,div.innerHTML})(viewUrl),hrefUrl=viewUrl.replace(/"/g,""");previewContainer.innerHTML='\n
\n Text link preview:
\n ').concat(linkText,'\n
This link will not be auto-converted by the MediaCMS filter.\n
\n ')}else{let previewWidth,previewHeight;if(values.responsive||"100%"===values.width||"100%"===values.height){const defaultDims={"16:9":{width:400,height:225},"4:3":{width:400,height:300},"1:1":{width:300,height:300}}[values.aspectRatio]||{width:400,height:225};previewWidth=defaultDims.width,previewHeight=defaultDims.height}else{previewWidth=Math.min(values.width,400);const scale=previewWidth/values.width;previewHeight=Math.round(values.height*scale)}previewContainer.innerHTML='\n \n \n ')}}handleInputChange(root){let updateUrlField=arguments.length>1&&void 0!==arguments[1]&&arguments[1];clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout((()=>{this.updatePreview(root,updateUrlField)}),500)}handleAspectRatioChange(root){const form=root.querySelector(_selectors.default.IFRAME.elements.form),aspectRatio=form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).value,dimensions=_selectors.default.IFRAME.aspectRatios[aspectRatio];dimensions&&"custom"!==aspectRatio&&(form.querySelector(_selectors.default.IFRAME.elements.width).value=dimensions.width,form.querySelector(_selectors.default.IFRAME.elements.height).value=dimensions.height),this.updatePreview(root)}toggleDimensionsEditability(root){const form=root.querySelector(_selectors.default.IFRAME.elements.form),responsiveCheckbox=form.querySelector(_selectors.default.IFRAME.elements.responsive),widthInput=form.querySelector(_selectors.default.IFRAME.elements.width),heightInput=form.querySelector(_selectors.default.IFRAME.elements.height);responsiveCheckbox.checked?(widthInput.disabled=!0,heightInput.disabled=!0,widthInput.style.opacity="0.5",heightInput.style.opacity="0.5",widthInput.value="100%",heightInput.value="100%"):(widthInput.disabled=!1,heightInput.disabled=!1,widthInput.style.opacity="1",heightInput.style.opacity="1")}handleWidthChange(root,newWidth){const form=root.querySelector(_selectors.default.IFRAME.elements.form),aspectRatio=form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).value,heightInput=form.querySelector(_selectors.default.IFRAME.elements.height);if("100%"!==newWidth){if("custom"!==aspectRatio&&newWidth){const width=parseInt(newWidth)||0,arr=aspectRatio.split(":"),x=parseInt(arr[0]),y=parseInt(arr[1]),calculatedHeight=Math.round(width*y/x);heightInput.value=calculatedHeight}this.handleInputChange(root)}else this.handleInputChange(root)}handleHeightChange(root,newHeight){const form=root.querySelector(_selectors.default.IFRAME.elements.form),aspectRatio=form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).value,widthInput=form.querySelector(_selectors.default.IFRAME.elements.width);if("100%"!==newHeight){if("custom"!==aspectRatio&&newHeight){const height=parseInt(newHeight)||0,arr=aspectRatio.split(":"),x=parseInt(arr[0]),y=parseInt(arr[1]),calculatedWidth=Math.round(height*x/y);widthInput.value=calculatedWidth}this.handleInputChange(root)}else this.handleInputChange(root)}async handleDialogueSubmission(modal){const root=modal.getRoot()[0],values=this.getFormValues(root);if(!values.url)return;const html=await this.generateIframeHtml(values);if(html)if(this.isUpdating&&this.selectedIframe){const wrapper=this.selectedIframe.closest(".tiny-mediacms-iframe-wrapper")||this.selectedIframe.closest(".tiny-iframe-responsive"),paragraphWrapper=wrapper?wrapper.closest("p"):this.selectedIframe.closest("p");paragraphWrapper?paragraphWrapper.outerHTML=html:wrapper?wrapper.outerHTML=html:this.selectedIframe.outerHTML=html,this.isUpdating=!1,this.editor.fire("Change")}else{const node=this.editor.selection.getNode();"P"===node.nodeName&&""===node.innerHTML.trim()?node.outerHTML=html:this.editor.insertContent(html)}}async handleRemove(modal){const confirmMessage=await(0,_str.getString)("removeiframeconfirm",_common.component);if(window.confirm(confirmMessage)){if(this.selectedIframe){const wrapper=this.selectedIframe.closest(".tiny-mediacms-iframe-wrapper")||this.selectedIframe.closest(".tiny-iframe-responsive");wrapper?wrapper.remove():this.selectedIframe.remove()}this.isUpdating=!1,modal.hide()}}async registerEventListeners(modal){await modal.getBody();const $root=modal.getRoot(),root=$root[0],form=root.querySelector(_selectors.default.IFRAME.elements.form);form.querySelector(_selectors.default.IFRAME.elements.url).addEventListener("input",(()=>this.handleInputChange(root))),[_selectors.default.IFRAME.elements.showTitle,_selectors.default.IFRAME.elements.linkTitle,_selectors.default.IFRAME.elements.showRelated,_selectors.default.IFRAME.elements.showUserAvatar,_selectors.default.IFRAME.elements.startAtEnabled].forEach((selector=>{form.querySelector(selector).addEventListener("change",(()=>this.handleInputChange(root,!0)))})),form.querySelector(_selectors.default.IFRAME.elements.responsive).addEventListener("change",(()=>{this.toggleDimensionsEditability(root),this.handleInputChange(root,!1)})),form.querySelector(_selectors.default.IFRAME.elements.textLinkOnly).addEventListener("change",(()=>this.handleInputChange(root,!1))),form.querySelector(_selectors.default.IFRAME.elements.startAt).addEventListener("input",(()=>this.handleInputChange(root,!0))),form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).addEventListener("change",(()=>this.handleAspectRatioChange(root))),form.querySelector(_selectors.default.IFRAME.elements.width).addEventListener("input",(e=>this.handleWidthChange(root,e.target.value))),form.querySelector(_selectors.default.IFRAME.elements.height).addEventListener("input",(e=>this.handleHeightChange(root,e.target.value))),$root.on(ModalEvents.save,(()=>this.handleDialogueSubmission(modal))),$root.on(ModalEvents.hidden,(()=>{this.currentModal.destroy()}));const removeBtn=root.querySelector(_selectors.default.IFRAME.actions.remove);removeBtn&&removeBtn.addEventListener("click",(()=>this.handleRemove(modal)));form.querySelector(_selectors.default.IFRAME.elements.url).value&&this.updatePreview(root);const iframeLibraryTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabIframeLibraryBtn);if(iframeLibraryTabBtn){iframeLibraryTabBtn.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation(),this.switchToIframeLibraryTab(root),setTimeout((()=>this.handleIframeLibraryTabClick(root)),100)})),iframeLibraryTabBtn.addEventListener("shown.bs.tab",(()=>this.handleIframeLibraryTabClick(root)));const $iframeLibraryTabBtn=window.jQuery?window.jQuery(iframeLibraryTabBtn):null;$iframeLibraryTabBtn&&$iframeLibraryTabBtn.on("shown.bs.tab",(()=>this.handleIframeLibraryTabClick(root)))}const urlTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabUrlBtn);urlTabBtn&&urlTabBtn.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation(),this.switchToUrlTab(root)})),this.registerIframeLibraryEventListeners(root),this.toggleDimensionsEditability(root),this.isUpdating?setTimeout((()=>this.updatePreview(root)),100):setTimeout((()=>this.handleIframeLibraryTabClick(root)),100)}switchToUrlTab(root){const form=root.querySelector(_selectors.default.IFRAME.elements.form),urlTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabUrlBtn),urlTabItem=form.querySelector(".tiny_iframecms_tab_url_item"),iframeLibraryTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabIframeLibraryBtn),urlPane=form.querySelector(_selectors.default.IFRAME.elements.paneUrl),iframeLibraryPane=form.querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);urlTabItem&&(urlTabItem.style.display=""),urlTabBtn&&(urlTabBtn.classList.add("active"),urlTabBtn.setAttribute("aria-selected","true")),iframeLibraryTabBtn&&(iframeLibraryTabBtn.classList.remove("active"),iframeLibraryTabBtn.setAttribute("aria-selected","false")),urlPane&&urlPane.classList.add("show","active"),iframeLibraryPane&&iframeLibraryPane.classList.remove("show","active")}switchToIframeLibraryTab(root){const form=root.querySelector(_selectors.default.IFRAME.elements.form),urlTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabUrlBtn),urlTabItem=form.querySelector(".tiny_iframecms_tab_url_item"),iframeLibraryTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabIframeLibraryBtn),urlPane=form.querySelector(_selectors.default.IFRAME.elements.paneUrl),iframeLibraryPane=form.querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);urlTabItem&&(urlTabItem.style.display="none"),urlTabBtn&&(urlTabBtn.classList.remove("active"),urlTabBtn.setAttribute("aria-selected","false")),iframeLibraryTabBtn&&(iframeLibraryTabBtn.classList.add("active"),iframeLibraryTabBtn.setAttribute("aria-selected","true")),urlPane&&urlPane.classList.remove("show","active"),iframeLibraryPane&&iframeLibraryPane.classList.add("show","active")}registerIframeLibraryEventListeners(root){window.addEventListener("message",(event=>{this.handleIframeLibraryMessage(root,event)}))}handleIframeLibraryTabClick(root){this.iframeLibraryLoaded=!1,this.loadIframeLibrary(root)}loadIframeLibrary(root){const ltiConfig=(0,_options.getLti)(this.editor);null!=ltiConfig&<iConfig.contentItemUrl?this.loadIframeLibraryViaLti(root):this.loadIframeLibraryStatic(root)}loadIframeLibraryViaLti(root){const pane=root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);if(!pane)return;const placeholderEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryPlaceholder),loadingEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryLoading),iframeEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryFrame);if(!iframeEl)return;placeholderEl&&placeholderEl.classList.add("d-none"),loadingEl&&loadingEl.classList.remove("d-none"),iframeEl.classList.add("d-none");iframeEl.addEventListener("load",(()=>{this.handleIframeLibraryLoad(root)}));const ltiConfig=(0,_options.getLti)(this.editor);iframeEl.src=ltiConfig.contentItemUrl}loadIframeLibraryStatic(root){const pane=root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);if(!pane)return;const placeholderEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryPlaceholder),loadingEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryLoading),iframeEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryFrame);if(!iframeEl)return;placeholderEl&&placeholderEl.classList.add("d-none"),loadingEl&&loadingEl.classList.remove("d-none"),iframeEl.classList.add("d-none");const loadHandler=()=>{iframeEl.src===this.iframeLibraryUrl&&(this.handleIframeLibraryLoad(root),iframeEl.removeEventListener("load",loadHandler))};iframeEl.addEventListener("load",loadHandler),iframeEl.src=this.iframeLibraryUrl}handleIframeLibraryLoad(root){const pane=root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);if(!pane)return;const placeholderEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryPlaceholder),loadingEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryLoading),iframeEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryFrame);placeholderEl&&placeholderEl.classList.add("d-none"),loadingEl&&loadingEl.classList.add("d-none"),iframeEl&&iframeEl.classList.remove("d-none"),this.iframeLibraryLoaded=!0}handleIframeLibraryMessage(root,event){const data=event.data;if(data)if("videoSelected"===data.type&&data.embedUrl)this.selectIframeLibraryVideo(root,data.embedUrl,data.videoId);else if("ltiDeepLinkingResponse"!==data.type&&"LtiDeepLinkingResponse"!==data.messageType)if("selectMedia"!==data.action&&"mediaSelected"!==data.action);else{const embedUrl=data.embedUrl||data.url||"",videoId=data.mediaId||data.videoId||data.id||"";embedUrl&&this.selectIframeLibraryVideo(root,embedUrl,videoId)}else{const contentItems=data.content_items||data.contentItems||[];if(contentItems.length>0){const item=contentItems[0],embedUrl=item.url||item.embed_url||item.embedUrl||"",videoId=item.id||item.mediaId||"";embedUrl&&this.selectIframeLibraryVideo(root,embedUrl,videoId)}}}selectIframeLibraryVideo(root,embedUrl,videoId){root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.url).value=embedUrl;const configureTabItem=root.querySelector(".tiny_iframecms_tab_url_item");configureTabItem&&(configureTabItem.style.display=""),this.switchToUrlTab(root),this.updatePreview(root),this.selectedLibraryVideo={embedUrl:embedUrl,videoId:videoId}}},_exports.default})); +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,"iframeLibraryLoaded",!1),_defineProperty(this,"selectedLibraryVideo",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(/]*src=["']([^"']+)["'][^>]*>/i);return iframeMatch?this.parseEmbedUrl(iframeMatch[1]):input.startsWith("http://")||input.startsWith("https://")?this.parseVideoUrl(input):null}parseVideoUrl(url){try{const urlObj=new URL(url),baseUrl="".concat(urlObj.protocol,"//").concat(urlObj.host);if("/view"===urlObj.pathname&&urlObj.searchParams.has("m"))return{baseUrl:baseUrl,videoId:urlObj.searchParams.get("m"),isEmbed:!1};if("/embed"===urlObj.pathname&&urlObj.searchParams.has("m")){const tParam=urlObj.searchParams.get("t"),widthParam=urlObj.searchParams.get("width"),heightParam=urlObj.searchParams.get("height");return{baseUrl:baseUrl,videoId:urlObj.searchParams.get("m"),isEmbed:!0,showTitle:"1"===urlObj.searchParams.get("showTitle"),linkTitle:"1"===urlObj.searchParams.get("linkTitle"),showRelated:"1"===urlObj.searchParams.get("showRelated"),showUserAvatar:"1"===urlObj.searchParams.get("showUserAvatar"),width:widthParam?parseInt(widthParam):null,height:heightParam?parseInt(heightParam):null,startAt:tParam?this.secondsToTimeString(parseInt(tParam)):null}}return urlObj.pathname.includes("/filter/mediacms/launch.php")&&urlObj.searchParams.has("token")?{baseUrl:baseUrl,videoId:urlObj.searchParams.get("token"),rawUrl:url,isLtiLaunch:!0}:{baseUrl:baseUrl,rawUrl:url,isGeneric:!0}}catch(e){return null}}parseEmbedUrl(url){return this.parseVideoUrl(url)}secondsToTimeString(seconds){const mins=Math.floor(seconds/60),secs=seconds%60;return"".concat(mins,":").concat(secs.toString().padStart(2,"0"))}timeStringToSeconds(timeStr){if(!timeStr||!timeStr.trim())return null;if((timeStr=timeStr.trim()).includes(":")){const parts=timeStr.split(":");return 60*(parseInt(parts[0])||0)+(parseInt(parts[1])||0)}const secs=parseInt(timeStr);return isNaN(secs)?null:secs}parseWidthHeight(value){if(!value)return null;const parsed=parseInt(value.trim());return isNaN(parsed)?null:parsed}buildEmbedUrl(parsed,options){if(parsed.isGeneric||parsed.isLtiLaunch)return parsed.rawUrl;const url=new URL("".concat(parsed.baseUrl,"/embed"));if(url.searchParams.set("m",parsed.videoId),url.searchParams.set("showTitle",options.showTitle?"1":"0"),url.searchParams.set("showRelated",options.showRelated?"1":"0"),url.searchParams.set("showUserAvatar",options.showUserAvatar?"1":"0"),url.searchParams.set("linkTitle",options.linkTitle?"1":"0"),options.width&&url.searchParams.set("width",options.width.toString()),options.height&&url.searchParams.set("height",options.height.toString()),options.startAtEnabled&&options.startAt){const seconds=this.timeStringToSeconds(options.startAt);null!==seconds&&seconds>0&&url.searchParams.set("t",seconds.toString())}return url.toString()}async getTemplateContext(){var _this=this;let data=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const editorData=(0,_options.getData)(this.editor),autoConvertOptions=(null==editorData?void 0:editorData.autoConvertOptions)||{},getDefault=function(key){let fallback=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return _this.isUpdating&&void 0!==data[key]?data[key]:void 0!==autoConvertOptions[key]?autoConvertOptions[key]:fallback};let width,height;return this.isUpdating&&(data.width||data.height)?(width=data.width||640,height=data.height||360):(width=640,height=360),{elementid:this.editor.getElement().id,isupdating:this.isUpdating,url:data.url||"",showTitle:getDefault("showTitle"),linkTitle:getDefault("linkTitle"),showRelated:getDefault("showRelated"),showUserAvatar:getDefault("showUserAvatar"),textLinkOnly:data.textLinkOnly||!1,startAtEnabled:data.startAtEnabled||!1,startAt:data.startAt||"0:00",width:width,height:height,is16_9:!data.aspectRatio||"16:9"===data.aspectRatio,is4_3:"4:3"===data.aspectRatio,is1_1:"1:1"===data.aspectRatio,isCustom:"custom"===data.aspectRatio}}async displayDialogue(){this.selectedIframe=this.getSelectedIframe();const data=this.getCurrentIframeData();this.isUpdating=null!==data,this.iframeLibraryLoaded=!1,this.currentModal=await _iframemodal.default.create({title:(0,_str.getString)("iframemodaltitle",_common.component),templateContext:await this.getTemplateContext(data||{})}),await this.registerEventListeners(this.currentModal)}getSelectedIframe(){const node=this.editor.selection.getNode();if("a"===node.nodeName.toLowerCase()&&"true"===node.getAttribute("data-mediacms-textlink"))return node;if("iframe"===node.nodeName.toLowerCase())return node;const iframe=node.querySelector("iframe");if(iframe)return iframe;const wrapper=node.closest(".tiny-mediacms-iframe-wrapper")||node.closest(".tiny-iframe-responsive");if(wrapper)return wrapper.querySelector("iframe");const textLink=node.closest('a[data-mediacms-textlink="true"]');return textLink||null}getCurrentIframeData(){var _parsed$showTitle2,_parsed$linkTitle2,_parsed$showRelated2,_parsed$showUserAvata2;if(!this.selectedIframe)return null;if("a"===this.selectedIframe.nodeName.toLowerCase()&&"true"===this.selectedIframe.getAttribute("data-mediacms-textlink")){var _parsed$showTitle,_parsed$linkTitle,_parsed$showRelated,_parsed$showUserAvata;const href=this.selectedIframe.getAttribute("href"),parsed=this.parseInput(href);return{url:href,width:(null==parsed?void 0:parsed.width)||560,height:(null==parsed?void 0:parsed.height)||315,showTitle:null===(_parsed$showTitle=null==parsed?void 0:parsed.showTitle)||void 0===_parsed$showTitle||_parsed$showTitle,linkTitle:null===(_parsed$linkTitle=null==parsed?void 0:parsed.linkTitle)||void 0===_parsed$linkTitle||_parsed$linkTitle,showRelated:null===(_parsed$showRelated=null==parsed?void 0:parsed.showRelated)||void 0===_parsed$showRelated||_parsed$showRelated,showUserAvatar:null===(_parsed$showUserAvata=null==parsed?void 0:parsed.showUserAvatar)||void 0===_parsed$showUserAvata||_parsed$showUserAvata,responsive:!0,textLinkOnly:!0,startAtEnabled:null!==(null==parsed?void 0:parsed.startAt),startAt:(null==parsed?void 0:parsed.startAt)||"0:00"}}const src=this.selectedIframe.getAttribute("src"),parsed=this.parseInput(src);let width=(null==parsed?void 0:parsed.width)||this.selectedIframe.getAttribute("width")||null,height=(null==parsed?void 0:parsed.height)||this.selectedIframe.getAttribute("height")||null;return width=width?parseInt(width):null,height=height?parseInt(height):null,{url:src,width:width,height:height,showTitle:null===(_parsed$showTitle2=null==parsed?void 0:parsed.showTitle)||void 0===_parsed$showTitle2||_parsed$showTitle2,linkTitle:null===(_parsed$linkTitle2=null==parsed?void 0:parsed.linkTitle)||void 0===_parsed$linkTitle2||_parsed$linkTitle2,showRelated:null===(_parsed$showRelated2=null==parsed?void 0:parsed.showRelated)||void 0===_parsed$showRelated2||_parsed$showRelated2,showUserAvatar:null===(_parsed$showUserAvata2=null==parsed?void 0:parsed.showUserAvatar)||void 0===_parsed$showUserAvata2||_parsed$showUserAvata2,startAtEnabled:null!==(null==parsed?void 0:parsed.startAt),startAt:(null==parsed?void 0:parsed.startAt)||"0:00"}}getFormValues(root){const form=root.querySelector(_selectors.default.IFRAME.elements.form);return{url:form.querySelector(_selectors.default.IFRAME.elements.url).value.trim(),showTitle:form.querySelector(_selectors.default.IFRAME.elements.showTitle).checked,linkTitle:form.querySelector(_selectors.default.IFRAME.elements.linkTitle).checked,showRelated:form.querySelector(_selectors.default.IFRAME.elements.showRelated).checked,showUserAvatar:form.querySelector(_selectors.default.IFRAME.elements.showUserAvatar).checked,textLinkOnly:form.querySelector(_selectors.default.IFRAME.elements.textLinkOnly).checked,startAtEnabled:form.querySelector(_selectors.default.IFRAME.elements.startAtEnabled).checked,startAt:form.querySelector(_selectors.default.IFRAME.elements.startAt).value.trim(),aspectRatio:form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).value,width:this.parseWidthHeight(form.querySelector(_selectors.default.IFRAME.elements.width).value),height:this.parseWidthHeight(form.querySelector(_selectors.default.IFRAME.elements.height).value)}}async generateIframeHtml(values){const parsed=this.parseInput(values.url);if(!parsed)return"";if(values.textLinkOnly){let viewUrl;viewUrl=parsed.isGeneric||parsed.isLtiLaunch?parsed.rawUrl:"".concat(parsed.baseUrl,"/view?m=").concat(parsed.videoId);const linkText=(str=>{const div=document.createElement("div");return div.textContent=str,div.innerHTML})(viewUrl),hrefUrl=viewUrl.replace(/"/g,""");return'

').concat(linkText,"

")}const context={src:this.buildEmbedUrl(parsed,values),width:values.width,height:values.height},{html:html}=await _templates.default.renderForPromise("tiny_mediacms/iframe_embed_output",context);return html}async updatePreview(root){let updateUrlField=arguments.length>1&&void 0!==arguments[1]&&arguments[1];const values=this.getFormValues(root),previewContainer=root.querySelector(_selectors.default.IFRAME.elements.preview),urlWarning=root.querySelector(_selectors.default.IFRAME.elements.urlWarning);if(!values.url)return previewContainer.innerHTML='Enter a video URL to see preview',void urlWarning.classList.add("d-none");const parsed=this.parseInput(values.url);if(!parsed)return previewContainer.innerHTML='Invalid URL format',void urlWarning.classList.remove("d-none");urlWarning.classList.add("d-none");const embedUrl=this.buildEmbedUrl(parsed,values);if(updateUrlField&&!parsed.isGeneric){root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.url).value=embedUrl}if(values.textLinkOnly){let viewUrl;viewUrl=parsed.isGeneric||parsed.isLtiLaunch?parsed.rawUrl:"".concat(parsed.baseUrl,"/view?m=").concat(parsed.videoId);const linkText=(str=>{const div=document.createElement("div");return div.textContent=str,div.innerHTML})(viewUrl),hrefUrl=viewUrl.replace(/"/g,""");previewContainer.innerHTML='\n
\n Text link preview:
\n ').concat(linkText,'\n
This link will not be auto-converted by the MediaCMS filter.\n
\n ')}else{const previewWidth=Math.min(values.width,400),scale=previewWidth/values.width,previewHeight=Math.round(values.height*scale);previewContainer.innerHTML='\n \n \n ')}}handleInputChange(root){let updateUrlField=arguments.length>1&&void 0!==arguments[1]&&arguments[1];clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout((()=>{this.updatePreview(root,updateUrlField)}),500)}handleAspectRatioChange(root){const form=root.querySelector(_selectors.default.IFRAME.elements.form),aspectRatio=form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).value,dimensions=_selectors.default.IFRAME.aspectRatios[aspectRatio];dimensions&&"custom"!==aspectRatio&&(form.querySelector(_selectors.default.IFRAME.elements.width).value=dimensions.width,form.querySelector(_selectors.default.IFRAME.elements.height).value=dimensions.height),this.updatePreview(root)}handleWidthChange(root,newWidth){const form=root.querySelector(_selectors.default.IFRAME.elements.form),aspectRatio=form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).value,heightInput=form.querySelector(_selectors.default.IFRAME.elements.height);if("custom"!==aspectRatio&&newWidth){const width=parseInt(newWidth)||0,arr=aspectRatio.split(":"),x=parseInt(arr[0]),y=parseInt(arr[1]),calculatedHeight=Math.round(width*y/x);heightInput.value=calculatedHeight}this.handleInputChange(root)}handleHeightChange(root,newHeight){const form=root.querySelector(_selectors.default.IFRAME.elements.form),aspectRatio=form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).value,widthInput=form.querySelector(_selectors.default.IFRAME.elements.width);if("custom"!==aspectRatio&&newHeight){const height=parseInt(newHeight)||0,arr=aspectRatio.split(":"),x=parseInt(arr[0]),y=parseInt(arr[1]),calculatedWidth=Math.round(height*x/y);widthInput.value=calculatedWidth}this.handleInputChange(root)}async handleDialogueSubmission(modal){const root=modal.getRoot()[0],values=this.getFormValues(root);if(!values.url)return;const html=await this.generateIframeHtml(values);if(html)if(this.isUpdating&&this.selectedIframe){const wrapper=this.selectedIframe.closest(".tiny-mediacms-iframe-wrapper")||this.selectedIframe.closest(".tiny-iframe-responsive"),paragraphWrapper=wrapper?wrapper.closest("p"):this.selectedIframe.closest("p");paragraphWrapper?paragraphWrapper.outerHTML=html:wrapper?wrapper.outerHTML=html:this.selectedIframe.outerHTML=html,this.isUpdating=!1,setTimeout((()=>{this.editor.getBody().querySelectorAll("p:empty, p:blank").forEach((p=>{""!==p.innerHTML.trim()&&"
"!==p.innerHTML||p.remove()}))}),10),this.editor.fire("Change")}else{const node=this.editor.selection.getNode();"P"===node.nodeName&&""===node.innerHTML.trim()?node.outerHTML=html:this.editor.insertContent(html)}}async handleRemove(modal){const confirmMessage=await(0,_str.getString)("removeiframeconfirm",_common.component);if(window.confirm(confirmMessage)){if(this.selectedIframe){const wrapper=this.selectedIframe.closest(".tiny-mediacms-iframe-wrapper")||this.selectedIframe.closest(".tiny-iframe-responsive");wrapper?wrapper.remove():this.selectedIframe.remove()}this.isUpdating=!1,modal.hide()}}async registerEventListeners(modal){await modal.getBody();const $root=modal.getRoot(),root=$root[0],form=root.querySelector(_selectors.default.IFRAME.elements.form);form.querySelector(_selectors.default.IFRAME.elements.url).addEventListener("input",(()=>this.handleInputChange(root))),[_selectors.default.IFRAME.elements.showTitle,_selectors.default.IFRAME.elements.linkTitle,_selectors.default.IFRAME.elements.showRelated,_selectors.default.IFRAME.elements.showUserAvatar,_selectors.default.IFRAME.elements.startAtEnabled].forEach((selector=>{form.querySelector(selector).addEventListener("change",(()=>this.handleInputChange(root,!0)))})),form.querySelector(_selectors.default.IFRAME.elements.textLinkOnly).addEventListener("change",(()=>this.handleInputChange(root,!1))),form.querySelector(_selectors.default.IFRAME.elements.startAt).addEventListener("input",(()=>this.handleInputChange(root,!0))),form.querySelector(_selectors.default.IFRAME.elements.aspectRatio).addEventListener("change",(()=>this.handleAspectRatioChange(root))),form.querySelector(_selectors.default.IFRAME.elements.width).addEventListener("input",(e=>this.handleWidthChange(root,e.target.value))),form.querySelector(_selectors.default.IFRAME.elements.height).addEventListener("input",(e=>this.handleHeightChange(root,e.target.value))),$root.on(ModalEvents.save,(()=>this.handleDialogueSubmission(modal))),$root.on(ModalEvents.hidden,(()=>{this.currentModal.destroy()}));const removeBtn=root.querySelector(_selectors.default.IFRAME.actions.remove);removeBtn&&removeBtn.addEventListener("click",(()=>this.handleRemove(modal)));form.querySelector(_selectors.default.IFRAME.elements.url).value&&this.updatePreview(root);const iframeLibraryTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabIframeLibraryBtn);if(iframeLibraryTabBtn){iframeLibraryTabBtn.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation(),this.switchToIframeLibraryTab(root),setTimeout((()=>this.handleIframeLibraryTabClick(root)),100)})),iframeLibraryTabBtn.addEventListener("shown.bs.tab",(()=>this.handleIframeLibraryTabClick(root)));const $iframeLibraryTabBtn=window.jQuery?window.jQuery(iframeLibraryTabBtn):null;$iframeLibraryTabBtn&&$iframeLibraryTabBtn.on("shown.bs.tab",(()=>this.handleIframeLibraryTabClick(root)))}const urlTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabUrlBtn);urlTabBtn&&urlTabBtn.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation(),this.switchToUrlTab(root)})),this.registerIframeLibraryEventListeners(root),this.isUpdating?setTimeout((()=>this.updatePreview(root)),100):setTimeout((()=>this.handleIframeLibraryTabClick(root)),100)}switchToUrlTab(root){const form=root.querySelector(_selectors.default.IFRAME.elements.form),urlTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabUrlBtn),urlTabItem=form.querySelector(".tiny_iframecms_tab_url_item"),iframeLibraryTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabIframeLibraryBtn),urlPane=form.querySelector(_selectors.default.IFRAME.elements.paneUrl),iframeLibraryPane=form.querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);urlTabItem&&(urlTabItem.style.display=""),urlTabBtn&&(urlTabBtn.classList.add("active"),urlTabBtn.setAttribute("aria-selected","true")),iframeLibraryTabBtn&&(iframeLibraryTabBtn.classList.remove("active"),iframeLibraryTabBtn.setAttribute("aria-selected","false")),urlPane&&urlPane.classList.add("show","active"),iframeLibraryPane&&iframeLibraryPane.classList.remove("show","active")}switchToIframeLibraryTab(root){const form=root.querySelector(_selectors.default.IFRAME.elements.form),urlTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabUrlBtn),urlTabItem=form.querySelector(".tiny_iframecms_tab_url_item"),iframeLibraryTabBtn=form.querySelector(_selectors.default.IFRAME.elements.tabIframeLibraryBtn),urlPane=form.querySelector(_selectors.default.IFRAME.elements.paneUrl),iframeLibraryPane=form.querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);urlTabItem&&(urlTabItem.style.display="none"),urlTabBtn&&(urlTabBtn.classList.remove("active"),urlTabBtn.setAttribute("aria-selected","false")),iframeLibraryTabBtn&&(iframeLibraryTabBtn.classList.add("active"),iframeLibraryTabBtn.setAttribute("aria-selected","true")),urlPane&&urlPane.classList.remove("show","active"),iframeLibraryPane&&iframeLibraryPane.classList.add("show","active")}registerIframeLibraryEventListeners(root){window.addEventListener("message",(event=>{this.handleIframeLibraryMessage(root,event)}))}handleIframeLibraryTabClick(root){this.iframeLibraryLoaded=!1,this.loadIframeLibrary(root)}loadIframeLibrary(root){const ltiConfig=(0,_options.getLti)(this.editor);null!=ltiConfig&<iConfig.contentItemUrl?this.loadIframeLibraryViaLti(root):this.loadIframeLibraryStatic(root)}loadIframeLibraryViaLti(root){const pane=root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);if(!pane)return;const placeholderEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryPlaceholder),loadingEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryLoading),iframeEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryFrame);if(!iframeEl)return;placeholderEl&&placeholderEl.classList.add("d-none"),loadingEl&&loadingEl.classList.remove("d-none"),iframeEl.classList.add("d-none");iframeEl.addEventListener("load",(()=>{this.handleIframeLibraryLoad(root)}));const ltiConfig=(0,_options.getLti)(this.editor);iframeEl.src=ltiConfig.contentItemUrl}loadIframeLibraryStatic(root){const pane=root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);if(!pane)return;const placeholderEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryPlaceholder),loadingEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryLoading),iframeEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryFrame);if(!iframeEl)return;placeholderEl&&placeholderEl.classList.add("d-none"),loadingEl&&loadingEl.classList.remove("d-none"),iframeEl.classList.add("d-none");const loadHandler=()=>{iframeEl.src===this.iframeLibraryUrl&&(this.handleIframeLibraryLoad(root),iframeEl.removeEventListener("load",loadHandler))};iframeEl.addEventListener("load",loadHandler),iframeEl.src=this.iframeLibraryUrl}handleIframeLibraryLoad(root){const pane=root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.paneIframeLibrary);if(!pane)return;const placeholderEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryPlaceholder),loadingEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryLoading),iframeEl=pane.querySelector(_selectors.default.IFRAME.elements.iframeLibraryFrame);placeholderEl&&placeholderEl.classList.add("d-none"),loadingEl&&loadingEl.classList.add("d-none"),iframeEl&&iframeEl.classList.remove("d-none"),this.iframeLibraryLoaded=!0}handleIframeLibraryMessage(root,event){const data=event.data;if(data)if("videoSelected"===data.type&&data.embedUrl)this.selectIframeLibraryVideo(root,data.embedUrl,data.videoId);else if("ltiDeepLinkingResponse"!==data.type&&"LtiDeepLinkingResponse"!==data.messageType)if("selectMedia"!==data.action&&"mediaSelected"!==data.action);else{const embedUrl=data.embedUrl||data.url||"",videoId=data.mediaId||data.videoId||data.id||"";embedUrl&&this.selectIframeLibraryVideo(root,embedUrl,videoId)}else{const contentItems=data.content_items||data.contentItems||[];if(contentItems.length>0){const item=contentItems[0],embedUrl=item.url||item.embed_url||item.embedUrl||"",videoId=item.id||item.mediaId||"";embedUrl&&this.selectIframeLibraryVideo(root,embedUrl,videoId)}}}selectIframeLibraryVideo(root,embedUrl,videoId){root.querySelector(_selectors.default.IFRAME.elements.form).querySelector(_selectors.default.IFRAME.elements.url).value=embedUrl;const configureTabItem=root.querySelector(".tiny_iframecms_tab_url_item");configureTabItem&&(configureTabItem.style.display=""),this.switchToUrlTab(root),this.updatePreview(root),this.selectedLibraryVideo={embedUrl:embedUrl,videoId:videoId}}},_exports.default})); //# sourceMappingURL=iframeembed.min.js.map \ No newline at end of file diff --git a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/iframeembed.min.js.map b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/iframeembed.min.js.map index aa4fbbfc..83deb581 100755 --- a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/iframeembed.min.js.map +++ b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/iframeembed.min.js.map @@ -1 +1 @@ -{"version":3,"file":"iframeembed.min.js","sources":["../src/iframeembed.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 Media2 Iframe Embed class.\n *\n * @module tiny_mediacms/iframeembed\n * @copyright 2024\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Templates from 'core/templates';\nimport { getString } from 'core/str';\nimport * as ModalEvents from 'core/modal_events';\nimport { component } from './common';\nimport IframeModal from './iframemodal';\nimport Selectors from './selectors';\nimport { getLti, getData } from './options';\n\nexport default class IframeEmbed {\n editor = null;\n currentModal = null;\n isUpdating = false;\n selectedIframe = null;\n debounceTimer = null;\n // Iframe library state\n iframeLibraryLoaded = false;\n selectedLibraryVideo = null;\n iframeLibraryUrl =\n 'https://temp.web357.com/mediacms/deic-mediacms-embed-videos.html';\n\n constructor(editor) {\n this.editor = editor;\n }\n\n /**\n * Parse input to extract video URL or iframe src.\n * Handles: iframe embed code, view URL, or embed URL.\n *\n * @param {string} input - The user input (URL or embed code)\n * @returns {Object|null} Parsed URL info or null if invalid\n */\n parseInput(input) {\n if (!input || !input.trim()) {\n return null;\n }\n\n input = input.trim();\n\n // Check if it's an iframe embed code\n const iframeMatch = input.match(\n /]*src=[\"']([^\"']+)[\"'][^>]*>/i,\n );\n if (iframeMatch) {\n return this.parseEmbedUrl(iframeMatch[1]);\n }\n\n // Check if it's a URL\n if (input.startsWith('http://') || input.startsWith('https://')) {\n return this.parseVideoUrl(input);\n }\n\n return null;\n }\n\n /**\n * Parse a video view URL and convert to embed format.\n *\n * @param {string} url - The video URL\n * @returns {Object|null} Parsed info\n */\n parseVideoUrl(url) {\n try {\n const urlObj = new URL(url);\n const baseUrl = `${urlObj.protocol}//${urlObj.host}`;\n\n // MediaCMS view URL: /view?m=VIDEO_ID\n if (urlObj.pathname === '/view' && urlObj.searchParams.has('m')) {\n return {\n baseUrl: baseUrl,\n videoId: urlObj.searchParams.get('m'),\n isEmbed: false,\n };\n }\n\n // MediaCMS embed URL: /embed?m=VIDEO_ID&options\n if (urlObj.pathname === '/embed' && urlObj.searchParams.has('m')) {\n const tParam = urlObj.searchParams.get('t');\n const widthParam = urlObj.searchParams.get('width');\n const heightParam = urlObj.searchParams.get('height');\n return {\n baseUrl: baseUrl,\n videoId: urlObj.searchParams.get('m'),\n isEmbed: true,\n showTitle: urlObj.searchParams.get('showTitle') === '1',\n linkTitle: urlObj.searchParams.get('linkTitle') === '1',\n showRelated: urlObj.searchParams.get('showRelated') === '1',\n showUserAvatar:\n urlObj.searchParams.get('showUserAvatar') === '1',\n width: widthParam ? parseInt(widthParam) : null,\n height: heightParam ? parseInt(heightParam) : null,\n startAt: tParam\n ? this.secondsToTimeString(parseInt(tParam))\n : null,\n };\n }\n\n // Moodle LTI launch.php URL: /filter/mediacms/launch.php?token=TOKEN\n // This is used when selecting from \"My Media\" via LTI\n // We treat it as a generic iframe URL (keep as-is)\n if (urlObj.pathname.includes('/filter/mediacms/launch.php') && urlObj.searchParams.has('token')) {\n return {\n baseUrl: baseUrl,\n videoId: urlObj.searchParams.get('token'),\n rawUrl: url,\n isLtiLaunch: true,\n };\n }\n\n // Generic URL - just use as-is\n return {\n baseUrl: baseUrl,\n rawUrl: url,\n isGeneric: true,\n };\n } catch (e) {\n return null;\n }\n }\n\n /**\n * Parse an embed URL.\n *\n * @param {string} url - The embed URL\n * @returns {Object|null} Parsed info\n */\n parseEmbedUrl(url) {\n return this.parseVideoUrl(url);\n }\n\n /**\n * Convert seconds to time string (M:SS format).\n *\n * @param {number} seconds - Time in seconds\n * @returns {string} Time string\n */\n secondsToTimeString(seconds) {\n const mins = Math.floor(seconds / 60);\n const secs = seconds % 60;\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n }\n\n /**\n * Convert time string to seconds.\n *\n * @param {string} timeStr - Time string (M:SS or just seconds)\n * @returns {number|null} Seconds or null if invalid\n */\n timeStringToSeconds(timeStr) {\n if (!timeStr || !timeStr.trim()) {\n return null;\n }\n timeStr = timeStr.trim();\n\n // Handle M:SS format\n if (timeStr.includes(':')) {\n const parts = timeStr.split(':');\n const mins = parseInt(parts[0]) || 0;\n const secs = parseInt(parts[1]) || 0;\n return mins * 60 + secs;\n }\n\n // Handle plain seconds\n const secs = parseInt(timeStr);\n return isNaN(secs) ? null : secs;\n }\n\n /**\n * Parse width/height value - handle both numeric and '100%'.\n *\n * @param {string} value - Width or height value\n * @returns {number|string|null} Parsed value\n */\n parseWidthHeight(value) {\n if (!value) {\n return null;\n }\n const trimmed = value.trim();\n if (trimmed === '100%') {\n return '100%';\n }\n const parsed = parseInt(trimmed);\n return isNaN(parsed) ? null : parsed;\n }\n\n /**\n * Build the embed URL with options.\n *\n * @param {Object} parsed - Parsed URL info\n * @param {Object} options - Embed options\n * @returns {string} The complete embed URL\n */\n buildEmbedUrl(parsed, options) {\n if (parsed.isGeneric || parsed.isLtiLaunch) {\n return parsed.rawUrl;\n }\n\n const url = new URL(`${parsed.baseUrl}/embed`);\n url.searchParams.set('m', parsed.videoId);\n\n // Always include all options with 1 or 0\n url.searchParams.set('showTitle', options.showTitle ? '1' : '0');\n url.searchParams.set('showRelated', options.showRelated ? '1' : '0');\n url.searchParams.set(\n 'showUserAvatar',\n options.showUserAvatar ? '1' : '0',\n );\n url.searchParams.set('linkTitle', options.linkTitle ? '1' : '0');\n\n // Add width and height ONLY if responsive is disabled and values are not 100%\n // When responsive is enabled, dimensions are set to 100% but not included in URL\n if (!options.responsive && options.width && options.width !== '100%') {\n url.searchParams.set('width', options.width.toString());\n }\n if (!options.responsive && options.height && options.height !== '100%') {\n url.searchParams.set('height', options.height.toString());\n }\n\n // Add start time if enabled\n if (options.startAtEnabled && options.startAt) {\n const seconds = this.timeStringToSeconds(options.startAt);\n if (seconds !== null && seconds > 0) {\n url.searchParams.set('t', seconds.toString());\n }\n }\n\n return url.toString();\n }\n\n /**\n * Get the template context for the modal.\n *\n * @param {Object} data - Existing data for updating\n * @returns {Object} Template context\n */\n async getTemplateContext(data = {}) {\n // Get admin settings for default checkbox values.\n const editorData = getData(this.editor);\n const autoConvertOptions = editorData?.autoConvertOptions || {};\n\n // Use admin settings as defaults when creating new embed (not updating).\n // When updating, use the values from the existing iframe.\n const getDefault = (key, fallback = true) => {\n if (this.isUpdating && data[key] !== undefined) {\n return data[key];\n }\n return autoConvertOptions[key] !== undefined\n ? autoConvertOptions[key]\n : fallback;\n };\n\n // Determine responsive mode:\n // - If editing with 100% dimensions, responsive is ON\n // - If editing with numeric dimensions, responsive is OFF\n // - Otherwise, default to responsive=ON for new embeds\n let isResponsive;\n if (this.isUpdating && (data.width || data.height)) {\n // Check if dimensions are 100% (responsive) or numeric (fixed)\n isResponsive = data.width === '100%' || data.height === '100%';\n } else {\n // New embed or no dimensions: responsive defaults to ON\n isResponsive = data.responsive !== false;\n }\n\n return {\n elementid: this.editor.getElement().id,\n isupdating: this.isUpdating,\n url: data.url || '',\n showTitle: getDefault('showTitle'),\n linkTitle: getDefault('linkTitle'),\n showRelated: getDefault('showRelated'),\n showUserAvatar: getDefault('showUserAvatar'),\n responsive: isResponsive,\n textLinkOnly: data.textLinkOnly || false,\n startAtEnabled: data.startAtEnabled || false,\n startAt: data.startAt || '0:00',\n // No default dimensions - only use provided values\n width: data.width || '',\n height: data.height || '',\n is16_9: !data.aspectRatio || data.aspectRatio === '16:9',\n is4_3: data.aspectRatio === '4:3',\n is1_1: data.aspectRatio === '1:1',\n isCustom: data.aspectRatio === 'custom',\n };\n }\n\n /**\n * Display the iframe embed dialog.\n */\n async displayDialogue() {\n this.selectedIframe = this.getSelectedIframe();\n const data = this.getCurrentIframeData();\n this.isUpdating = data !== null;\n\n // Reset iframe library state for new modal\n this.iframeLibraryLoaded = false;\n\n this.currentModal = await IframeModal.create({\n title: getString('iframemodaltitle', component),\n templateContext: await this.getTemplateContext(data || {}),\n });\n\n await this.registerEventListeners(this.currentModal);\n }\n\n /**\n * Get the currently selected iframe or text link in the editor.\n *\n * @returns {HTMLElement|null} The iframe element, text link, or null\n */\n getSelectedIframe() {\n const node = this.editor.selection.getNode();\n\n // Check if it's a text-only link\n if (node.nodeName.toLowerCase() === 'a' && node.getAttribute('data-mediacms-textlink') === 'true') {\n return node;\n }\n\n if (node.nodeName.toLowerCase() === 'iframe') {\n return node;\n }\n\n // Check if selection contains an iframe wrapper (including overlay wrapper)\n const iframe = node.querySelector('iframe');\n if (iframe) {\n return iframe;\n }\n\n // Check if we're on the overlay or wrapper and need to find the iframe\n const wrapper =\n node.closest('.tiny-mediacms-iframe-wrapper') ||\n node.closest('.tiny-iframe-responsive');\n if (wrapper) {\n return wrapper.querySelector('iframe');\n }\n\n // Check if we're inside a text-only link\n const textLink = node.closest('a[data-mediacms-textlink=\"true\"]');\n if (textLink) {\n return textLink;\n }\n\n return null;\n }\n\n /**\n * Get current iframe or text link data for editing.\n *\n * @returns {Object|null} Current iframe/link data or null\n */\n getCurrentIframeData() {\n if (!this.selectedIframe) {\n return null;\n }\n\n // Check if it's a text-only link\n if (this.selectedIframe.nodeName.toLowerCase() === 'a' &&\n this.selectedIframe.getAttribute('data-mediacms-textlink') === 'true') {\n const href = this.selectedIframe.getAttribute('href');\n const parsed = this.parseInput(href);\n\n return {\n url: href,\n width: parsed?.width || 560,\n height: parsed?.height || 315,\n showTitle: parsed?.showTitle ?? true,\n linkTitle: parsed?.linkTitle ?? true,\n showRelated: parsed?.showRelated ?? true,\n showUserAvatar: parsed?.showUserAvatar ?? true,\n responsive: true,\n textLinkOnly: true,\n startAtEnabled: parsed?.startAt !== null,\n startAt: parsed?.startAt || '0:00',\n };\n }\n\n // Handle iframe\n const src = this.selectedIframe.getAttribute('src');\n const parsed = this.parseInput(src);\n\n // Get width/height from URL params or iframe attributes\n let width = parsed?.width || this.selectedIframe.getAttribute('width') || null;\n let height = parsed?.height || this.selectedIframe.getAttribute('height') || null;\n\n // Check if responsive: either by style (aspect-ratio) or by 100% dimensions\n const style = this.selectedIframe.getAttribute('style') || '';\n const hasAspectRatio = style.includes('aspect-ratio');\n const has100Percent = width === '100%' || height === '100%';\n const isResponsive = hasAspectRatio || has100Percent;\n\n // If responsive, set both to 100%\n if (isResponsive) {\n width = '100%';\n height = '100%';\n } else {\n // Parse numeric values\n width = width ? parseInt(width) : null;\n height = height ? parseInt(height) : null;\n }\n\n return {\n url: src,\n width: width,\n height: height,\n showTitle: parsed?.showTitle ?? true,\n linkTitle: parsed?.linkTitle ?? true,\n showRelated: parsed?.showRelated ?? true,\n showUserAvatar: parsed?.showUserAvatar ?? true,\n responsive: isResponsive,\n startAtEnabled: parsed?.startAt !== null,\n startAt: parsed?.startAt || '0:00',\n };\n }\n\n /**\n * Get form values from the modal.\n *\n * @param {HTMLElement} root - Modal root element\n * @returns {Object} Form values\n */\n getFormValues(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n return {\n url: form.querySelector(Selectors.IFRAME.elements.url).value.trim(),\n showTitle: form.querySelector(Selectors.IFRAME.elements.showTitle)\n .checked,\n linkTitle: form.querySelector(Selectors.IFRAME.elements.linkTitle)\n .checked,\n showRelated: form.querySelector(\n Selectors.IFRAME.elements.showRelated,\n ).checked,\n showUserAvatar: form.querySelector(\n Selectors.IFRAME.elements.showUserAvatar,\n ).checked,\n responsive: form.querySelector(Selectors.IFRAME.elements.responsive)\n .checked,\n textLinkOnly: form.querySelector(Selectors.IFRAME.elements.textLinkOnly)\n .checked,\n startAtEnabled: form.querySelector(\n Selectors.IFRAME.elements.startAtEnabled,\n ).checked,\n startAt: form\n .querySelector(Selectors.IFRAME.elements.startAt)\n .value.trim(),\n aspectRatio: form.querySelector(\n Selectors.IFRAME.elements.aspectRatio,\n ).value,\n width: this.parseWidthHeight(\n form.querySelector(Selectors.IFRAME.elements.width).value,\n ),\n height: this.parseWidthHeight(\n form.querySelector(Selectors.IFRAME.elements.height).value,\n ),\n };\n }\n\n /**\n * Generate the iframe HTML or text link.\n *\n * @param {Object} values - Form values\n * @returns {Promise} Generated HTML\n */\n async generateIframeHtml(values) {\n const parsed = this.parseInput(values.url);\n if (!parsed) {\n return '';\n }\n\n // If user selected \"text link only\", generate a link instead of iframe\n if (values.textLinkOnly) {\n // Build the view URL (not embed URL) for the link\n let viewUrl;\n if (parsed.isGeneric || parsed.isLtiLaunch) {\n // For generic URLs and LTI launch URLs, use as-is\n viewUrl = parsed.rawUrl;\n } else {\n // For MediaCMS URLs, convert to view URL\n viewUrl = `${parsed.baseUrl}/view?m=${parsed.videoId}`;\n }\n\n // Use the full URL as the link text\n // Escape HTML entities in the URL for safe display\n const escapeHtml = (str) => {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n };\n\n const linkText = escapeHtml(viewUrl);\n const hrefUrl = viewUrl.replace(/\"/g, '"');\n\n // Add data attribute to mark this as a text-only link\n // This prevents the filter from converting it to an LTI launch iframe\n return `

${linkText}

`;\n }\n\n const embedUrl = this.buildEmbedUrl(parsed, values);\n\n // Calculate aspect ratio values for CSS\n const aspectRatioCalcs = {\n '16:9': '16 / 9',\n '4:3': '4 / 3',\n '1:1': '1 / 1',\n custom: `${values.width} / ${values.height}`,\n };\n\n const context = {\n src: embedUrl,\n width: values.width,\n height: values.height,\n responsive: values.responsive,\n aspectRatioCalc: aspectRatioCalcs[values.aspectRatio] || '16 / 9',\n aspectRatioValue: aspectRatioCalcs[values.aspectRatio] || '16 / 9',\n };\n\n const { html } = await Templates.renderForPromise(\n 'tiny_mediacms/iframe_embed_output',\n context,\n );\n return html;\n }\n\n /**\n * Update the preview in the modal.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {boolean} updateUrlField - Whether to update the URL field with new embed options\n */\n async updatePreview(root, updateUrlField = false) {\n const values = this.getFormValues(root);\n const previewContainer = root.querySelector(\n Selectors.IFRAME.elements.preview,\n );\n const urlWarning = root.querySelector(\n Selectors.IFRAME.elements.urlWarning,\n );\n\n if (!values.url) {\n previewContainer.innerHTML =\n 'Enter a video URL to see preview';\n urlWarning.classList.add('d-none');\n return;\n }\n\n const parsed = this.parseInput(values.url);\n if (!parsed) {\n previewContainer.innerHTML =\n 'Invalid URL format';\n urlWarning.classList.remove('d-none');\n return;\n }\n\n urlWarning.classList.add('d-none');\n const embedUrl = this.buildEmbedUrl(parsed, values);\n\n // Update the URL field if requested (when embed options change)\n if (updateUrlField && !parsed.isGeneric) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const urlInput = form.querySelector(Selectors.IFRAME.elements.url);\n urlInput.value = embedUrl;\n }\n\n // If text link only is selected, show link preview\n if (values.textLinkOnly) {\n let viewUrl;\n if (parsed.isGeneric || parsed.isLtiLaunch) {\n viewUrl = parsed.rawUrl;\n } else {\n viewUrl = `${parsed.baseUrl}/view?m=${parsed.videoId}`;\n }\n\n // Escape HTML entities for safe display\n const escapeHtml = (str) => {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n };\n\n const linkText = escapeHtml(viewUrl);\n const hrefUrl = viewUrl.replace(/\"/g, '"');\n\n previewContainer.innerHTML = `\n
\n Text link preview:
\n ${linkText}\n
This link will not be auto-converted by the MediaCMS filter.\n
\n `;\n } else {\n // Show a scaled preview\n let previewWidth, previewHeight;\n\n if (values.responsive || values.width === '100%' || values.height === '100%') {\n // For responsive, use default preview dimensions with aspect ratio\n const aspectRatioCalcs = {\n '16:9': { width: 400, height: 225 },\n '4:3': { width: 400, height: 300 },\n '1:1': { width: 300, height: 300 },\n };\n const defaultDims = aspectRatioCalcs[values.aspectRatio] || { width: 400, height: 225 };\n previewWidth = defaultDims.width;\n previewHeight = defaultDims.height;\n } else {\n // For fixed dimensions, scale to fit preview\n previewWidth = Math.min(values.width, 400);\n const scale = previewWidth / values.width;\n previewHeight = Math.round(values.height * scale);\n }\n\n previewContainer.innerHTML = `\n \n \n `;\n }\n }\n\n /**\n * Handle form input changes with debounce.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {boolean} updateUrlField - Whether to update the URL field\n */\n handleInputChange(root, updateUrlField = false) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = setTimeout(() => {\n this.updatePreview(root, updateUrlField);\n }, 500);\n }\n\n /**\n * Handle aspect ratio change - update dimensions.\n *\n * @param {HTMLElement} root - Modal root element\n */\n handleAspectRatioChange(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const aspectRatio = form.querySelector(\n Selectors.IFRAME.elements.aspectRatio,\n ).value;\n const dimensions = Selectors.IFRAME.aspectRatios[aspectRatio];\n\n // Only update dimensions for predefined ratios, not 'custom'\n if (dimensions && aspectRatio !== 'custom') {\n form.querySelector(Selectors.IFRAME.elements.width).value =\n dimensions.width;\n form.querySelector(Selectors.IFRAME.elements.height).value =\n dimensions.height;\n }\n\n this.updatePreview(root);\n }\n\n /**\n * Toggle width/height input editability based on responsive mode.\n *\n * @param {HTMLElement} root - Modal root element\n */\n toggleDimensionsEditability(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const responsiveCheckbox = form.querySelector(Selectors.IFRAME.elements.responsive);\n const widthInput = form.querySelector(Selectors.IFRAME.elements.width);\n const heightInput = form.querySelector(Selectors.IFRAME.elements.height);\n\n if (responsiveCheckbox.checked) {\n // Responsive mode: disable width/height inputs and set to 100%\n widthInput.disabled = true;\n heightInput.disabled = true;\n widthInput.style.opacity = '0.5';\n heightInput.style.opacity = '0.5';\n // Set to 100% to indicate responsive mode\n widthInput.value = '100%';\n heightInput.value = '100%';\n } else {\n // Fixed mode: enable width/height inputs (no defaults)\n widthInput.disabled = false;\n heightInput.disabled = false;\n widthInput.style.opacity = '1';\n heightInput.style.opacity = '1';\n // Leave values as-is (empty if no dimensions specified)\n }\n }\n\n /**\n * Handle width change - adjust height to maintain aspect ratio.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {string} newWidth - New width value\n */\n handleWidthChange(root, newWidth) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const aspectRatio = form.querySelector(Selectors.IFRAME.elements.aspectRatio).value;\n const heightInput = form.querySelector(Selectors.IFRAME.elements.height);\n\n // Skip calculation if value is 100% (responsive mode)\n if (newWidth === '100%') {\n this.handleInputChange(root);\n return;\n }\n\n // Only adjust height if aspect ratio is not 'custom'\n if (aspectRatio !== 'custom' && newWidth) {\n const width = parseInt(newWidth) || 0;\n const arr = aspectRatio.split(':');\n const x = parseInt(arr[0]);\n const y = parseInt(arr[1]);\n\n // Calculate height based on aspect ratio: height = (width * y) / x\n const calculatedHeight = Math.round((width * y) / x);\n heightInput.value = calculatedHeight;\n }\n\n this.handleInputChange(root);\n }\n\n /**\n * Handle height change - adjust width to maintain aspect ratio.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {string} newHeight - New height value\n */\n handleHeightChange(root, newHeight) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const aspectRatio = form.querySelector(Selectors.IFRAME.elements.aspectRatio).value;\n const widthInput = form.querySelector(Selectors.IFRAME.elements.width);\n\n // Skip calculation if value is 100% (responsive mode)\n if (newHeight === '100%') {\n this.handleInputChange(root);\n return;\n }\n\n // Only adjust width if aspect ratio is not 'custom'\n if (aspectRatio !== 'custom' && newHeight) {\n const height = parseInt(newHeight) || 0;\n const arr = aspectRatio.split(':');\n const x = parseInt(arr[0]);\n const y = parseInt(arr[1]);\n\n // Calculate width based on aspect ratio: width = (height * x) / y\n const calculatedWidth = Math.round((height * x) / y);\n widthInput.value = calculatedWidth;\n }\n\n this.handleInputChange(root);\n }\n\n /**\n * Handle dialog submission.\n *\n * @param {Object} modal - The modal instance\n */\n async handleDialogueSubmission(modal) {\n const root = modal.getRoot()[0];\n const values = this.getFormValues(root);\n\n if (!values.url) {\n return;\n }\n\n const html = await this.generateIframeHtml(values);\n if (html) {\n if (this.isUpdating && this.selectedIframe) {\n // Replace existing iframe (including wrapper if present)\n // Check for both old wrapper and new overlay wrapper\n const wrapper =\n this.selectedIframe.closest(\n '.tiny-mediacms-iframe-wrapper',\n ) || this.selectedIframe.closest('.tiny-iframe-responsive');\n\n // Also check if iframe is inside a

tag and remove it\n const paragraphWrapper = wrapper ? wrapper.closest('p') : this.selectedIframe.closest('p');\n\n if (paragraphWrapper) {\n // Replace the entire paragraph to avoid empty

tags\n paragraphWrapper.outerHTML = html;\n } else if (wrapper) {\n wrapper.outerHTML = html;\n } else {\n this.selectedIframe.outerHTML = html;\n }\n this.isUpdating = false;\n // Fire change event to trigger overlay reprocessing\n this.editor.fire('Change');\n } else {\n // Insert content without wrapping in paragraph tags\n // Use setContent if cursor is in an empty paragraph, otherwise insertContent\n const node = this.editor.selection.getNode();\n if (node.nodeName === 'P' && node.innerHTML.trim() === '') {\n // Replace empty paragraph with iframe\n node.outerHTML = html;\n } else {\n this.editor.insertContent(html);\n }\n }\n }\n }\n\n /**\n * Handle video removal from the editor.\n *\n * @param {Object} modal - The modal instance\n */\n async handleRemove(modal) {\n // Get confirmation string\n const confirmMessage = await getString(\n 'removeiframeconfirm',\n component,\n );\n\n // Show confirmation dialog\n // eslint-disable-next-line no-alert\n if (!window.confirm(confirmMessage)) {\n return;\n }\n\n if (this.selectedIframe) {\n // Remove the iframe (including wrapper if present)\n const wrapper =\n this.selectedIframe.closest('.tiny-mediacms-iframe-wrapper') ||\n this.selectedIframe.closest('.tiny-iframe-responsive');\n if (wrapper) {\n wrapper.remove();\n } else {\n this.selectedIframe.remove();\n }\n }\n\n // Close the modal\n this.isUpdating = false;\n modal.hide();\n }\n\n /**\n * Register event listeners for the modal.\n *\n * @param {Object} modal - The modal instance\n */\n async registerEventListeners(modal) {\n await modal.getBody();\n const $root = modal.getRoot();\n const root = $root[0];\n\n // Input change handlers\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n // URL input\n form.querySelector(Selectors.IFRAME.elements.url).addEventListener(\n 'input',\n () => this.handleInputChange(root),\n );\n\n // Embed option checkboxes - these should update the URL field when changed\n [\n Selectors.IFRAME.elements.showTitle,\n Selectors.IFRAME.elements.linkTitle,\n Selectors.IFRAME.elements.showRelated,\n Selectors.IFRAME.elements.showUserAvatar,\n Selectors.IFRAME.elements.startAtEnabled,\n ].forEach((selector) => {\n form.querySelector(selector).addEventListener('change', () =>\n this.handleInputChange(root, true), // Update URL field when embed options change\n );\n });\n\n // Responsive checkbox - toggle width/height editability\n form.querySelector(Selectors.IFRAME.elements.responsive).addEventListener('change', () => {\n this.toggleDimensionsEditability(root);\n this.handleInputChange(root, false);\n });\n\n // Text link only checkbox - doesn't affect URL, only output format\n form.querySelector(Selectors.IFRAME.elements.textLinkOnly).addEventListener('change', () =>\n this.handleInputChange(root, false),\n );\n\n // Start at time input - should update URL field\n form.querySelector(Selectors.IFRAME.elements.startAt).addEventListener(\n 'input',\n () => this.handleInputChange(root, true),\n );\n\n // Aspect ratio change\n form.querySelector(\n Selectors.IFRAME.elements.aspectRatio,\n ).addEventListener('change', () => this.handleAspectRatioChange(root));\n\n // Dimension inputs - maintain aspect ratio when changed\n form.querySelector(Selectors.IFRAME.elements.width).addEventListener(\n 'input',\n (e) => this.handleWidthChange(root, e.target.value),\n );\n form.querySelector(Selectors.IFRAME.elements.height).addEventListener(\n 'input',\n (e) => this.handleHeightChange(root, e.target.value),\n );\n\n // Modal events\n $root.on(ModalEvents.save, () => this.handleDialogueSubmission(modal));\n $root.on(ModalEvents.hidden, () => {\n this.currentModal.destroy();\n });\n\n // Remove button handler (only present when updating)\n const removeBtn = root.querySelector(Selectors.IFRAME.actions.remove);\n if (removeBtn) {\n removeBtn.addEventListener('click', () => this.handleRemove(modal));\n }\n\n // Initial preview if we have a URL\n const urlInput = form.querySelector(Selectors.IFRAME.elements.url);\n if (urlInput.value) {\n this.updatePreview(root);\n }\n\n // Tab change handler - load iframe library when switching to iframe library tab\n const iframeLibraryTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabIframeLibraryBtn,\n );\n if (iframeLibraryTabBtn) {\n iframeLibraryTabBtn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n\n // Manually handle tab switching for Bootstrap 5\n this.switchToIframeLibraryTab(root);\n\n // Small delay to ensure tab pane is visible before loading iframe\n setTimeout(() => this.handleIframeLibraryTabClick(root), 100);\n });\n // Also handle Bootstrap tab events (if Bootstrap handles it)\n iframeLibraryTabBtn.addEventListener('shown.bs.tab', () =>\n this.handleIframeLibraryTabClick(root),\n );\n // jQuery Bootstrap 4 event\n const $iframeLibraryTabBtn = window.jQuery\n ? window.jQuery(iframeLibraryTabBtn)\n : null;\n if ($iframeLibraryTabBtn) {\n $iframeLibraryTabBtn.on('shown.bs.tab', () =>\n this.handleIframeLibraryTabClick(root),\n );\n }\n }\n\n // Tab change handler for URL tab\n const urlTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabUrlBtn,\n );\n if (urlTabBtn) {\n urlTabBtn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n\n // Manually handle tab switching\n this.switchToUrlTab(root);\n });\n }\n\n // Iframe library event listeners\n this.registerIframeLibraryEventListeners(root);\n\n // Set initial state of width/height inputs based on responsive checkbox\n this.toggleDimensionsEditability(root);\n\n // If editing, Configure tab is active - update preview immediately\n // If inserting, My Media tab is active - load the library\n if (this.isUpdating) {\n // When editing, Configure tab is already active, just update preview\n setTimeout(() => this.updatePreview(root), 100);\n } else {\n // When inserting, load My Media library tab\n setTimeout(() => this.handleIframeLibraryTabClick(root), 100);\n }\n }\n\n /**\n * Switch to the URL tab.\n *\n * @param {HTMLElement} root - Modal root element\n */\n switchToUrlTab(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n // Get tab buttons\n const urlTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabUrlBtn,\n );\n const urlTabItem = form.querySelector('.tiny_iframecms_tab_url_item');\n const iframeLibraryTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabIframeLibraryBtn,\n );\n\n // Get tab panes\n const urlPane = form.querySelector(Selectors.IFRAME.elements.paneUrl);\n const iframeLibraryPane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n // Show the Configure tab\n if (urlTabItem) {\n urlTabItem.style.display = '';\n }\n\n // Update tab button states\n if (urlTabBtn) {\n urlTabBtn.classList.add('active');\n urlTabBtn.setAttribute('aria-selected', 'true');\n }\n if (iframeLibraryTabBtn) {\n iframeLibraryTabBtn.classList.remove('active');\n iframeLibraryTabBtn.setAttribute('aria-selected', 'false');\n }\n\n // Update tab pane visibility\n if (urlPane) {\n urlPane.classList.add('show', 'active');\n }\n if (iframeLibraryPane) {\n iframeLibraryPane.classList.remove('show', 'active');\n }\n }\n\n /**\n * Switch to the iframe library tab.\n *\n * @param {HTMLElement} root - Modal root element\n */\n switchToIframeLibraryTab(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n // Get tab buttons\n const urlTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabUrlBtn,\n );\n const urlTabItem = form.querySelector('.tiny_iframecms_tab_url_item');\n const iframeLibraryTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabIframeLibraryBtn,\n );\n\n // Get tab panes\n const urlPane = form.querySelector(Selectors.IFRAME.elements.paneUrl);\n const iframeLibraryPane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n // Hide the Configure tab when switching to My Media\n if (urlTabItem) {\n urlTabItem.style.display = 'none';\n }\n\n // Update tab button states\n if (urlTabBtn) {\n urlTabBtn.classList.remove('active');\n urlTabBtn.setAttribute('aria-selected', 'false');\n }\n if (iframeLibraryTabBtn) {\n iframeLibraryTabBtn.classList.add('active');\n iframeLibraryTabBtn.setAttribute('aria-selected', 'true');\n }\n\n // Update tab pane visibility\n if (urlPane) {\n urlPane.classList.remove('show', 'active');\n }\n if (iframeLibraryPane) {\n iframeLibraryPane.classList.add('show', 'active');\n }\n }\n\n /**\n * Register event listeners for the iframe library.\n *\n * @param {HTMLElement} root - Modal root element\n */\n registerIframeLibraryEventListeners(root) {\n // Listen for messages from the iframe (for video selection)\n window.addEventListener('message', (event) => {\n this.handleIframeLibraryMessage(root, event);\n });\n }\n\n /**\n * Handle iframe library tab click - always refetch content (no caching).\n *\n * @param {HTMLElement} root - Modal root element\n */\n handleIframeLibraryTabClick(root) {\n // Always refetch content when tab is clicked (no caching)\n // Reset the loaded state to ensure fresh content is fetched\n this.iframeLibraryLoaded = false;\n this.loadIframeLibrary(root);\n }\n\n /**\n * Load the iframe library using LTI flow or fallback to static URL.\n *\n * @param {HTMLElement} root - Modal root element\n */\n loadIframeLibrary(root) {\n const ltiConfig = getLti(this.editor);\n // Check if LTI is configured with a content item URL\n if (ltiConfig?.contentItemUrl) {\n this.loadIframeLibraryViaLti(root);\n } else {\n // Fallback to static URL if LTI not configured\n this.loadIframeLibraryStatic(root);\n }\n }\n\n /**\n * Load the iframe library via LTI Deep Linking (Content Item Selection).\n * Sets the iframe src to contentitem.php which initiates the LTI Deep Linking flow.\n * This sends an LtiDeepLinkingRequest message, which will redirect to the\n * tool's content selection interface (e.g., /lti/select-media/).\n *\n * @param {HTMLElement} root - Modal root element\n */\n loadIframeLibraryViaLti(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const pane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n if (!pane) { return;\n }\n\n const placeholderEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryPlaceholder,\n );\n const loadingEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryLoading,\n );\n const iframeEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryFrame,\n );\n\n if (!iframeEl) { return;\n }\n\n // Hide placeholder, show loading state\n if (placeholderEl) {\n placeholderEl.classList.add('d-none');\n }\n if (loadingEl) {\n loadingEl.classList.remove('d-none');\n }\n iframeEl.classList.add('d-none');\n\n // Set up load listener - note: this may fire multiple times during LTI redirects\n const loadHandler = () => { this.handleIframeLibraryLoad(root);\n };\n iframeEl.addEventListener('load', loadHandler);\n\n // Set the iframe src to the content item URL\n // This initiates the LTI Deep Linking flow:\n // 1. contentitem.php initiates OIDC login\n // 2. LTI provider authenticates\n // 3. Moodle sends LtiDeepLinkingRequest\n // 4. Tool provider shows content selection interface\n const ltiConfig = getLti(this.editor);\n iframeEl.src = ltiConfig.contentItemUrl;\n }\n\n /**\n * Load the iframe library using static URL (fallback).\n *\n * @param {HTMLElement} root - Modal root element\n */\n loadIframeLibraryStatic(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const pane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n if (!pane) { return;\n }\n\n const placeholderEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryPlaceholder,\n );\n const loadingEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryLoading,\n );\n const iframeEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryFrame,\n );\n if (!iframeEl) { return;\n }\n\n // Hide placeholder, show loading state\n if (placeholderEl) {\n placeholderEl.classList.add('d-none');\n }\n if (loadingEl) {\n loadingEl.classList.remove('d-none');\n }\n iframeEl.classList.add('d-none');\n\n // Set up load listener before setting src\n const loadHandler = () => { // Only handle if the src matches our target URL\n if (iframeEl.src === this.iframeLibraryUrl) {\n this.handleIframeLibraryLoad(root);\n // Remove the listener after successful load\n iframeEl.removeEventListener('load', loadHandler);\n }\n };\n iframeEl.addEventListener('load', loadHandler);\n\n // Set the iframe source\n iframeEl.src = this.iframeLibraryUrl; }\n\n /**\n * Handle iframe library load event.\n *\n * @param {HTMLElement} root - Modal root element\n */\n handleIframeLibraryLoad(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const pane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n if (!pane) {\n return;\n }\n\n const placeholderEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryPlaceholder,\n );\n const loadingEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryLoading,\n );\n const iframeEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryFrame,\n );\n\n // Hide placeholder and loading, show iframe\n if (placeholderEl) {\n placeholderEl.classList.add('d-none');\n }\n if (loadingEl) {\n loadingEl.classList.add('d-none');\n }\n if (iframeEl) {\n iframeEl.classList.remove('d-none');\n }\n\n this.iframeLibraryLoaded = true;\n }\n\n /**\n * Handle messages from the iframe library (for video selection).\n * Supports both custom videoSelected messages and LTI Deep Linking responses.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {MessageEvent} event - The message event\n */\n handleIframeLibraryMessage(root, event) {\n const data = event.data;\n\n if (!data) {\n return;\n }\n\n // Handle custom videoSelected message format\n if (data.type === 'videoSelected' && data.embedUrl) {\n this.selectIframeLibraryVideo(root, data.embedUrl, data.videoId);\n return;\n }\n\n // Handle LTI Deep Linking response format\n if (\n data.type === 'ltiDeepLinkingResponse' ||\n data.messageType === 'LtiDeepLinkingResponse'\n ) { const contentItems = data.content_items || data.contentItems || [];\n if (contentItems.length > 0) {\n const item = contentItems[0];\n // Extract embed URL from the content item\n const embedUrl =\n item.url || item.embed_url || item.embedUrl || '';\n const videoId = item.id || item.mediaId || '';\n if (embedUrl) { this.selectIframeLibraryVideo(root, embedUrl, videoId);\n }\n }\n return;\n }\n\n // Handle MediaCMS specific message format (if different from above)\n if (data.action === 'selectMedia' || data.action === 'mediaSelected') {\n const embedUrl = data.embedUrl || data.url || '';\n const videoId = data.mediaId || data.videoId || data.id || '';\n if (embedUrl) { this.selectIframeLibraryVideo(root, embedUrl, videoId);\n }\n return;\n }\n }\n\n /**\n * Select a video from the iframe library and populate the URL field.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {string} embedUrl - The embed URL for the video\n * @param {string} videoId - The video ID\n */\n selectIframeLibraryVideo(root, embedUrl, videoId) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n // Populate the URL field\n const urlInput = form.querySelector(Selectors.IFRAME.elements.url);\n urlInput.value = embedUrl;\n\n // Show the Configure tab (it starts hidden)\n const configureTabItem = root.querySelector('.tiny_iframecms_tab_url_item');\n if (configureTabItem) {\n configureTabItem.style.display = '';\n }\n\n // Switch to the Configure tab to show embed options\n this.switchToUrlTab(root);\n\n // Update the preview\n this.updatePreview(root);\n\n // Store the selected video\n this.selectedLibraryVideo = { embedUrl, videoId };\n }\n}\n"],"names":["constructor","editor","parseInput","input","trim","iframeMatch","match","this","parseEmbedUrl","startsWith","parseVideoUrl","url","urlObj","URL","baseUrl","protocol","host","pathname","searchParams","has","videoId","get","isEmbed","tParam","widthParam","heightParam","showTitle","linkTitle","showRelated","showUserAvatar","width","parseInt","height","startAt","secondsToTimeString","includes","rawUrl","isLtiLaunch","isGeneric","e","seconds","mins","Math","floor","secs","toString","padStart","timeStringToSeconds","timeStr","parts","split","isNaN","parseWidthHeight","value","trimmed","parsed","buildEmbedUrl","options","set","responsive","startAtEnabled","data","editorData","autoConvertOptions","getDefault","key","fallback","_this","isUpdating","undefined","isResponsive","elementid","getElement","id","isupdating","textLinkOnly","is16_9","aspectRatio","is4_3","is1_1","isCustom","selectedIframe","getSelectedIframe","getCurrentIframeData","iframeLibraryLoaded","currentModal","IframeModal","create","title","component","templateContext","getTemplateContext","registerEventListeners","node","selection","getNode","nodeName","toLowerCase","getAttribute","iframe","querySelector","wrapper","closest","textLink","href","src","getFormValues","root","form","Selectors","IFRAME","elements","checked","values","viewUrl","linkText","str","div","document","createElement","textContent","innerHTML","escapeHtml","hrefUrl","replace","embedUrl","aspectRatioCalcs","custom","context","aspectRatioCalc","aspectRatioValue","html","Templates","renderForPromise","updateUrlField","previewContainer","preview","urlWarning","classList","add","remove","previewWidth","previewHeight","defaultDims","min","scale","round","handleInputChange","clearTimeout","debounceTimer","setTimeout","updatePreview","handleAspectRatioChange","dimensions","aspectRatios","toggleDimensionsEditability","responsiveCheckbox","widthInput","heightInput","disabled","style","opacity","handleWidthChange","newWidth","arr","x","y","calculatedHeight","handleHeightChange","newHeight","calculatedWidth","modal","getRoot","generateIframeHtml","paragraphWrapper","outerHTML","fire","insertContent","confirmMessage","window","confirm","hide","getBody","$root","addEventListener","forEach","selector","target","on","ModalEvents","save","handleDialogueSubmission","hidden","destroy","removeBtn","actions","handleRemove","iframeLibraryTabBtn","tabIframeLibraryBtn","preventDefault","stopPropagation","switchToIframeLibraryTab","handleIframeLibraryTabClick","$iframeLibraryTabBtn","jQuery","urlTabBtn","tabUrlBtn","switchToUrlTab","registerIframeLibraryEventListeners","urlTabItem","urlPane","paneUrl","iframeLibraryPane","paneIframeLibrary","display","setAttribute","event","handleIframeLibraryMessage","loadIframeLibrary","ltiConfig","contentItemUrl","loadIframeLibraryViaLti","loadIframeLibraryStatic","pane","placeholderEl","iframeLibraryPlaceholder","loadingEl","iframeLibraryLoading","iframeEl","iframeLibraryFrame","handleIframeLibraryLoad","loadHandler","iframeLibraryUrl","removeEventListener","type","selectIframeLibraryVideo","messageType","action","mediaId","contentItems","content_items","length","item","embed_url","configureTabItem","selectedLibraryVideo"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"iframeembed.min.js","sources":["../src/iframeembed.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 Media2 Iframe Embed class.\n *\n * @module tiny_mediacms/iframeembed\n * @copyright 2024\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Templates from 'core/templates';\nimport { getString } from 'core/str';\nimport * as ModalEvents from 'core/modal_events';\nimport { component } from './common';\nimport IframeModal from './iframemodal';\nimport Selectors from './selectors';\nimport { getLti, getData } from './options';\n\nexport default class IframeEmbed {\n editor = null;\n currentModal = null;\n isUpdating = false;\n selectedIframe = null;\n debounceTimer = null;\n // Iframe library state\n iframeLibraryLoaded = false;\n selectedLibraryVideo = null;\n iframeLibraryUrl =\n 'https://temp.web357.com/mediacms/deic-mediacms-embed-videos.html';\n\n constructor(editor) {\n this.editor = editor;\n }\n\n /**\n * Parse input to extract video URL or iframe src.\n * Handles: iframe embed code, view URL, or embed URL.\n *\n * @param {string} input - The user input (URL or embed code)\n * @returns {Object|null} Parsed URL info or null if invalid\n */\n parseInput(input) {\n if (!input || !input.trim()) {\n return null;\n }\n\n input = input.trim();\n\n // Check if it's an iframe embed code\n const iframeMatch = input.match(\n /]*src=[\"']([^\"']+)[\"'][^>]*>/i,\n );\n if (iframeMatch) {\n return this.parseEmbedUrl(iframeMatch[1]);\n }\n\n // Check if it's a URL\n if (input.startsWith('http://') || input.startsWith('https://')) {\n return this.parseVideoUrl(input);\n }\n\n return null;\n }\n\n /**\n * Parse a video view URL and convert to embed format.\n *\n * @param {string} url - The video URL\n * @returns {Object|null} Parsed info\n */\n parseVideoUrl(url) {\n try {\n const urlObj = new URL(url);\n const baseUrl = `${urlObj.protocol}//${urlObj.host}`;\n\n // MediaCMS view URL: /view?m=VIDEO_ID\n if (urlObj.pathname === '/view' && urlObj.searchParams.has('m')) {\n return {\n baseUrl: baseUrl,\n videoId: urlObj.searchParams.get('m'),\n isEmbed: false,\n };\n }\n\n // MediaCMS embed URL: /embed?m=VIDEO_ID&options\n if (urlObj.pathname === '/embed' && urlObj.searchParams.has('m')) {\n const tParam = urlObj.searchParams.get('t');\n const widthParam = urlObj.searchParams.get('width');\n const heightParam = urlObj.searchParams.get('height');\n return {\n baseUrl: baseUrl,\n videoId: urlObj.searchParams.get('m'),\n isEmbed: true,\n showTitle: urlObj.searchParams.get('showTitle') === '1',\n linkTitle: urlObj.searchParams.get('linkTitle') === '1',\n showRelated: urlObj.searchParams.get('showRelated') === '1',\n showUserAvatar:\n urlObj.searchParams.get('showUserAvatar') === '1',\n width: widthParam ? parseInt(widthParam) : null,\n height: heightParam ? parseInt(heightParam) : null,\n startAt: tParam\n ? this.secondsToTimeString(parseInt(tParam))\n : null,\n };\n }\n\n // Moodle LTI launch.php URL: /filter/mediacms/launch.php?token=TOKEN\n // This is used when selecting from \"My Media\" via LTI\n // We treat it as a generic iframe URL (keep as-is)\n if (urlObj.pathname.includes('/filter/mediacms/launch.php') && urlObj.searchParams.has('token')) {\n return {\n baseUrl: baseUrl,\n videoId: urlObj.searchParams.get('token'),\n rawUrl: url,\n isLtiLaunch: true,\n };\n }\n\n // Generic URL - just use as-is\n return {\n baseUrl: baseUrl,\n rawUrl: url,\n isGeneric: true,\n };\n } catch (e) {\n return null;\n }\n }\n\n /**\n * Parse an embed URL.\n *\n * @param {string} url - The embed URL\n * @returns {Object|null} Parsed info\n */\n parseEmbedUrl(url) {\n return this.parseVideoUrl(url);\n }\n\n /**\n * Convert seconds to time string (M:SS format).\n *\n * @param {number} seconds - Time in seconds\n * @returns {string} Time string\n */\n secondsToTimeString(seconds) {\n const mins = Math.floor(seconds / 60);\n const secs = seconds % 60;\n return `${mins}:${secs.toString().padStart(2, '0')}`;\n }\n\n /**\n * Convert time string to seconds.\n *\n * @param {string} timeStr - Time string (M:SS or just seconds)\n * @returns {number|null} Seconds or null if invalid\n */\n timeStringToSeconds(timeStr) {\n if (!timeStr || !timeStr.trim()) {\n return null;\n }\n timeStr = timeStr.trim();\n\n // Handle M:SS format\n if (timeStr.includes(':')) {\n const parts = timeStr.split(':');\n const mins = parseInt(parts[0]) || 0;\n const secs = parseInt(parts[1]) || 0;\n return mins * 60 + secs;\n }\n\n // Handle plain seconds\n const secs = parseInt(timeStr);\n return isNaN(secs) ? null : secs;\n }\n\n /**\n * Parse width/height value.\n *\n * @param {string} value - Width or height value\n * @returns {number|null} Parsed value\n */\n parseWidthHeight(value) {\n if (!value) {\n return null;\n }\n const parsed = parseInt(value.trim());\n return isNaN(parsed) ? null : parsed;\n }\n\n /**\n * Build the embed URL with options.\n *\n * @param {Object} parsed - Parsed URL info\n * @param {Object} options - Embed options\n * @returns {string} The complete embed URL\n */\n buildEmbedUrl(parsed, options) {\n if (parsed.isGeneric || parsed.isLtiLaunch) {\n return parsed.rawUrl;\n }\n\n const url = new URL(`${parsed.baseUrl}/embed`);\n url.searchParams.set('m', parsed.videoId);\n\n // Always include all options with 1 or 0\n url.searchParams.set('showTitle', options.showTitle ? '1' : '0');\n url.searchParams.set('showRelated', options.showRelated ? '1' : '0');\n url.searchParams.set(\n 'showUserAvatar',\n options.showUserAvatar ? '1' : '0',\n );\n url.searchParams.set('linkTitle', options.linkTitle ? '1' : '0');\n\n // Add width and height if provided\n if (options.width) {\n url.searchParams.set('width', options.width.toString());\n }\n if (options.height) {\n url.searchParams.set('height', options.height.toString());\n }\n\n // Add start time if enabled\n if (options.startAtEnabled && options.startAt) {\n const seconds = this.timeStringToSeconds(options.startAt);\n if (seconds !== null && seconds > 0) {\n url.searchParams.set('t', seconds.toString());\n }\n }\n\n return url.toString();\n }\n\n /**\n * Get the template context for the modal.\n *\n * @param {Object} data - Existing data for updating\n * @returns {Object} Template context\n */\n async getTemplateContext(data = {}) {\n // Get admin settings for default checkbox values.\n const editorData = getData(this.editor);\n const autoConvertOptions = editorData?.autoConvertOptions || {};\n\n // Use admin settings as defaults when creating new embed (not updating).\n // When updating, use the values from the existing iframe.\n const getDefault = (key, fallback = true) => {\n if (this.isUpdating && data[key] !== undefined) {\n return data[key];\n }\n return autoConvertOptions[key] !== undefined\n ? autoConvertOptions[key]\n : fallback;\n };\n\n // Determine dimensions:\n // - For editing: preserve existing dimensions\n // - For new embeds: default to 640x360\n let width, height;\n\n if (this.isUpdating && (data.width || data.height)) {\n // Editing: preserve existing dimensions\n width = data.width || 640;\n height = data.height || 360;\n } else {\n // New embed: default to 640x360 (16:9 aspect ratio)\n width = 640;\n height = 360;\n }\n\n return {\n elementid: this.editor.getElement().id,\n isupdating: this.isUpdating,\n url: data.url || '',\n showTitle: getDefault('showTitle'),\n linkTitle: getDefault('linkTitle'),\n showRelated: getDefault('showRelated'),\n showUserAvatar: getDefault('showUserAvatar'),\n textLinkOnly: data.textLinkOnly || false,\n startAtEnabled: data.startAtEnabled || false,\n startAt: data.startAt || '0:00',\n width: width,\n height: height,\n is16_9: !data.aspectRatio || data.aspectRatio === '16:9',\n is4_3: data.aspectRatio === '4:3',\n is1_1: data.aspectRatio === '1:1',\n isCustom: data.aspectRatio === 'custom',\n };\n }\n\n /**\n * Display the iframe embed dialog.\n */\n async displayDialogue() {\n this.selectedIframe = this.getSelectedIframe();\n const data = this.getCurrentIframeData();\n this.isUpdating = data !== null;\n\n // Reset iframe library state for new modal\n this.iframeLibraryLoaded = false;\n\n this.currentModal = await IframeModal.create({\n title: getString('iframemodaltitle', component),\n templateContext: await this.getTemplateContext(data || {}),\n });\n\n await this.registerEventListeners(this.currentModal);\n }\n\n /**\n * Get the currently selected iframe or text link in the editor.\n *\n * @returns {HTMLElement|null} The iframe element, text link, or null\n */\n getSelectedIframe() {\n const node = this.editor.selection.getNode();\n\n // Check if it's a text-only link\n if (node.nodeName.toLowerCase() === 'a' && node.getAttribute('data-mediacms-textlink') === 'true') {\n return node;\n }\n\n if (node.nodeName.toLowerCase() === 'iframe') {\n return node;\n }\n\n // Check if selection contains an iframe wrapper (including overlay wrapper)\n const iframe = node.querySelector('iframe');\n if (iframe) {\n return iframe;\n }\n\n // Check if we're on the overlay or wrapper and need to find the iframe\n const wrapper =\n node.closest('.tiny-mediacms-iframe-wrapper') ||\n node.closest('.tiny-iframe-responsive');\n if (wrapper) {\n return wrapper.querySelector('iframe');\n }\n\n // Check if we're inside a text-only link\n const textLink = node.closest('a[data-mediacms-textlink=\"true\"]');\n if (textLink) {\n return textLink;\n }\n\n return null;\n }\n\n /**\n * Get current iframe or text link data for editing.\n *\n * @returns {Object|null} Current iframe/link data or null\n */\n getCurrentIframeData() {\n if (!this.selectedIframe) {\n return null;\n }\n\n // Check if it's a text-only link\n if (this.selectedIframe.nodeName.toLowerCase() === 'a' &&\n this.selectedIframe.getAttribute('data-mediacms-textlink') === 'true') {\n const href = this.selectedIframe.getAttribute('href');\n const parsed = this.parseInput(href);\n\n return {\n url: href,\n width: parsed?.width || 560,\n height: parsed?.height || 315,\n showTitle: parsed?.showTitle ?? true,\n linkTitle: parsed?.linkTitle ?? true,\n showRelated: parsed?.showRelated ?? true,\n showUserAvatar: parsed?.showUserAvatar ?? true,\n responsive: true,\n textLinkOnly: true,\n startAtEnabled: parsed?.startAt !== null,\n startAt: parsed?.startAt || '0:00',\n };\n }\n\n // Handle iframe\n const src = this.selectedIframe.getAttribute('src');\n const parsed = this.parseInput(src);\n\n // Get width/height from URL params or iframe attributes\n let width = parsed?.width || this.selectedIframe.getAttribute('width') || null;\n let height = parsed?.height || this.selectedIframe.getAttribute('height') || null;\n\n // Parse numeric values\n width = width ? parseInt(width) : null;\n height = height ? parseInt(height) : null;\n\n return {\n url: src,\n width: width,\n height: height,\n showTitle: parsed?.showTitle ?? true,\n linkTitle: parsed?.linkTitle ?? true,\n showRelated: parsed?.showRelated ?? true,\n showUserAvatar: parsed?.showUserAvatar ?? true,\n startAtEnabled: parsed?.startAt !== null,\n startAt: parsed?.startAt || '0:00',\n };\n }\n\n /**\n * Get form values from the modal.\n *\n * @param {HTMLElement} root - Modal root element\n * @returns {Object} Form values\n */\n getFormValues(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n return {\n url: form.querySelector(Selectors.IFRAME.elements.url).value.trim(),\n showTitle: form.querySelector(Selectors.IFRAME.elements.showTitle)\n .checked,\n linkTitle: form.querySelector(Selectors.IFRAME.elements.linkTitle)\n .checked,\n showRelated: form.querySelector(\n Selectors.IFRAME.elements.showRelated,\n ).checked,\n showUserAvatar: form.querySelector(\n Selectors.IFRAME.elements.showUserAvatar,\n ).checked,\n textLinkOnly: form.querySelector(Selectors.IFRAME.elements.textLinkOnly)\n .checked,\n startAtEnabled: form.querySelector(\n Selectors.IFRAME.elements.startAtEnabled,\n ).checked,\n startAt: form\n .querySelector(Selectors.IFRAME.elements.startAt)\n .value.trim(),\n aspectRatio: form.querySelector(\n Selectors.IFRAME.elements.aspectRatio,\n ).value,\n width: this.parseWidthHeight(\n form.querySelector(Selectors.IFRAME.elements.width).value,\n ),\n height: this.parseWidthHeight(\n form.querySelector(Selectors.IFRAME.elements.height).value,\n ),\n };\n }\n\n /**\n * Generate the iframe HTML or text link.\n *\n * @param {Object} values - Form values\n * @returns {Promise} Generated HTML\n */\n async generateIframeHtml(values) {\n const parsed = this.parseInput(values.url);\n if (!parsed) {\n return '';\n }\n\n // If user selected \"text link only\", generate a link instead of iframe\n if (values.textLinkOnly) {\n // Build the view URL (not embed URL) for the link\n let viewUrl;\n if (parsed.isGeneric || parsed.isLtiLaunch) {\n // For generic URLs and LTI launch URLs, use as-is\n viewUrl = parsed.rawUrl;\n } else {\n // For MediaCMS URLs, convert to view URL\n viewUrl = `${parsed.baseUrl}/view?m=${parsed.videoId}`;\n }\n\n // Use the full URL as the link text\n // Escape HTML entities in the URL for safe display\n const escapeHtml = (str) => {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n };\n\n const linkText = escapeHtml(viewUrl);\n const hrefUrl = viewUrl.replace(/\"/g, '"');\n\n // Add data attribute to mark this as a text-only link\n // This prevents the filter from converting it to an LTI launch iframe\n return `

${linkText}

`;\n }\n\n const embedUrl = this.buildEmbedUrl(parsed, values);\n\n const context = {\n src: embedUrl,\n width: values.width,\n height: values.height,\n };\n\n const { html } = await Templates.renderForPromise(\n 'tiny_mediacms/iframe_embed_output',\n context,\n );\n return html;\n }\n\n /**\n * Update the preview in the modal.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {boolean} updateUrlField - Whether to update the URL field with new embed options\n */\n async updatePreview(root, updateUrlField = false) {\n const values = this.getFormValues(root);\n const previewContainer = root.querySelector(\n Selectors.IFRAME.elements.preview,\n );\n const urlWarning = root.querySelector(\n Selectors.IFRAME.elements.urlWarning,\n );\n\n if (!values.url) {\n previewContainer.innerHTML =\n 'Enter a video URL to see preview';\n urlWarning.classList.add('d-none');\n return;\n }\n\n const parsed = this.parseInput(values.url);\n if (!parsed) {\n previewContainer.innerHTML =\n 'Invalid URL format';\n urlWarning.classList.remove('d-none');\n return;\n }\n\n urlWarning.classList.add('d-none');\n const embedUrl = this.buildEmbedUrl(parsed, values);\n\n // Update the URL field if requested (when embed options change)\n if (updateUrlField && !parsed.isGeneric) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const urlInput = form.querySelector(Selectors.IFRAME.elements.url);\n urlInput.value = embedUrl;\n }\n\n // If text link only is selected, show link preview\n if (values.textLinkOnly) {\n let viewUrl;\n if (parsed.isGeneric || parsed.isLtiLaunch) {\n viewUrl = parsed.rawUrl;\n } else {\n viewUrl = `${parsed.baseUrl}/view?m=${parsed.videoId}`;\n }\n\n // Escape HTML entities for safe display\n const escapeHtml = (str) => {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n };\n\n const linkText = escapeHtml(viewUrl);\n const hrefUrl = viewUrl.replace(/\"/g, '"');\n\n previewContainer.innerHTML = `\n
\n Text link preview:
\n ${linkText}\n
This link will not be auto-converted by the MediaCMS filter.\n
\n `;\n } else {\n // Show a scaled preview - scale to fit preview area\n const previewWidth = Math.min(values.width, 400);\n const scale = previewWidth / values.width;\n const previewHeight = Math.round(values.height * scale);\n\n previewContainer.innerHTML = `\n \n \n `;\n }\n }\n\n /**\n * Handle form input changes with debounce.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {boolean} updateUrlField - Whether to update the URL field\n */\n handleInputChange(root, updateUrlField = false) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = setTimeout(() => {\n this.updatePreview(root, updateUrlField);\n }, 500);\n }\n\n /**\n * Handle aspect ratio change - update dimensions.\n *\n * @param {HTMLElement} root - Modal root element\n */\n handleAspectRatioChange(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const aspectRatio = form.querySelector(\n Selectors.IFRAME.elements.aspectRatio,\n ).value;\n const dimensions = Selectors.IFRAME.aspectRatios[aspectRatio];\n\n // Only update dimensions for predefined ratios, not 'custom'\n if (dimensions && aspectRatio !== 'custom') {\n form.querySelector(Selectors.IFRAME.elements.width).value =\n dimensions.width;\n form.querySelector(Selectors.IFRAME.elements.height).value =\n dimensions.height;\n }\n\n this.updatePreview(root);\n }\n\n /**\n * Toggle width/height input editability based on responsive mode.\n *\n * @param {HTMLElement} root - Modal root element\n */\n\n /**\n * Handle width change - adjust height to maintain aspect ratio.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {string} newWidth - New width value\n */\n handleWidthChange(root, newWidth) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const aspectRatio = form.querySelector(Selectors.IFRAME.elements.aspectRatio).value;\n const heightInput = form.querySelector(Selectors.IFRAME.elements.height);\n\n // Only adjust height if aspect ratio is not 'custom'\n if (aspectRatio !== 'custom' && newWidth) {\n const width = parseInt(newWidth) || 0;\n const arr = aspectRatio.split(':');\n const x = parseInt(arr[0]);\n const y = parseInt(arr[1]);\n\n // Calculate height based on aspect ratio: height = (width * y) / x\n const calculatedHeight = Math.round((width * y) / x);\n heightInput.value = calculatedHeight;\n }\n\n this.handleInputChange(root);\n }\n\n /**\n * Handle height change - adjust width to maintain aspect ratio.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {string} newHeight - New height value\n */\n handleHeightChange(root, newHeight) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const aspectRatio = form.querySelector(Selectors.IFRAME.elements.aspectRatio).value;\n const widthInput = form.querySelector(Selectors.IFRAME.elements.width);\n\n // Only adjust width if aspect ratio is not 'custom'\n if (aspectRatio !== 'custom' && newHeight) {\n const height = parseInt(newHeight) || 0;\n const arr = aspectRatio.split(':');\n const x = parseInt(arr[0]);\n const y = parseInt(arr[1]);\n\n // Calculate width based on aspect ratio: width = (height * x) / y\n const calculatedWidth = Math.round((height * x) / y);\n widthInput.value = calculatedWidth;\n }\n\n this.handleInputChange(root);\n }\n\n /**\n * Handle dialog submission.\n *\n * @param {Object} modal - The modal instance\n */\n async handleDialogueSubmission(modal) {\n const root = modal.getRoot()[0];\n const values = this.getFormValues(root);\n\n if (!values.url) {\n return;\n }\n\n const html = await this.generateIframeHtml(values);\n if (html) {\n if (this.isUpdating && this.selectedIframe) {\n // Replace existing iframe (including wrapper if present)\n // Check for both old wrapper and new overlay wrapper\n const wrapper =\n this.selectedIframe.closest(\n '.tiny-mediacms-iframe-wrapper',\n ) || this.selectedIframe.closest('.tiny-iframe-responsive');\n\n // Check if iframe is inside a

tag\n const paragraphWrapper = wrapper ? wrapper.closest('p') : this.selectedIframe.closest('p');\n\n if (paragraphWrapper) {\n // Replace the entire paragraph to avoid empty

tags\n paragraphWrapper.outerHTML = html;\n } else if (wrapper) {\n wrapper.outerHTML = html;\n } else {\n this.selectedIframe.outerHTML = html;\n }\n this.isUpdating = false;\n\n // Clean up any empty paragraph tags left behind\n setTimeout(() => {\n const body = this.editor.getBody();\n const emptyPs = body.querySelectorAll('p:empty, p:blank');\n emptyPs.forEach(p => {\n if (p.innerHTML.trim() === '' || p.innerHTML === '
') {\n p.remove();\n }\n });\n }, 10);\n\n // Fire change event to trigger overlay reprocessing\n this.editor.fire('Change');\n } else {\n // Insert content without wrapping in paragraph tags\n // Use setContent if cursor is in an empty paragraph, otherwise insertContent\n const node = this.editor.selection.getNode();\n if (node.nodeName === 'P' && node.innerHTML.trim() === '') {\n // Replace empty paragraph with iframe\n node.outerHTML = html;\n } else {\n this.editor.insertContent(html);\n }\n }\n }\n }\n\n /**\n * Handle video removal from the editor.\n *\n * @param {Object} modal - The modal instance\n */\n async handleRemove(modal) {\n // Get confirmation string\n const confirmMessage = await getString(\n 'removeiframeconfirm',\n component,\n );\n\n // Show confirmation dialog\n // eslint-disable-next-line no-alert\n if (!window.confirm(confirmMessage)) {\n return;\n }\n\n if (this.selectedIframe) {\n // Remove the iframe (including wrapper if present)\n const wrapper =\n this.selectedIframe.closest('.tiny-mediacms-iframe-wrapper') ||\n this.selectedIframe.closest('.tiny-iframe-responsive');\n if (wrapper) {\n wrapper.remove();\n } else {\n this.selectedIframe.remove();\n }\n }\n\n // Close the modal\n this.isUpdating = false;\n modal.hide();\n }\n\n /**\n * Register event listeners for the modal.\n *\n * @param {Object} modal - The modal instance\n */\n async registerEventListeners(modal) {\n await modal.getBody();\n const $root = modal.getRoot();\n const root = $root[0];\n\n // Input change handlers\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n // URL input\n form.querySelector(Selectors.IFRAME.elements.url).addEventListener(\n 'input',\n () => this.handleInputChange(root),\n );\n\n // Embed option checkboxes - these should update the URL field when changed\n [\n Selectors.IFRAME.elements.showTitle,\n Selectors.IFRAME.elements.linkTitle,\n Selectors.IFRAME.elements.showRelated,\n Selectors.IFRAME.elements.showUserAvatar,\n Selectors.IFRAME.elements.startAtEnabled,\n ].forEach((selector) => {\n form.querySelector(selector).addEventListener('change', () =>\n this.handleInputChange(root, true), // Update URL field when embed options change\n );\n });\n\n // Text link only checkbox - doesn't affect URL, only output format\n form.querySelector(Selectors.IFRAME.elements.textLinkOnly).addEventListener('change', () =>\n this.handleInputChange(root, false),\n );\n\n // Start at time input - should update URL field\n form.querySelector(Selectors.IFRAME.elements.startAt).addEventListener(\n 'input',\n () => this.handleInputChange(root, true),\n );\n\n // Aspect ratio change\n form.querySelector(\n Selectors.IFRAME.elements.aspectRatio,\n ).addEventListener('change', () => this.handleAspectRatioChange(root));\n\n // Dimension inputs - maintain aspect ratio when changed\n form.querySelector(Selectors.IFRAME.elements.width).addEventListener(\n 'input',\n (e) => this.handleWidthChange(root, e.target.value),\n );\n form.querySelector(Selectors.IFRAME.elements.height).addEventListener(\n 'input',\n (e) => this.handleHeightChange(root, e.target.value),\n );\n\n // Modal events\n $root.on(ModalEvents.save, () => this.handleDialogueSubmission(modal));\n $root.on(ModalEvents.hidden, () => {\n this.currentModal.destroy();\n });\n\n // Remove button handler (only present when updating)\n const removeBtn = root.querySelector(Selectors.IFRAME.actions.remove);\n if (removeBtn) {\n removeBtn.addEventListener('click', () => this.handleRemove(modal));\n }\n\n // Initial preview if we have a URL\n const urlInput = form.querySelector(Selectors.IFRAME.elements.url);\n if (urlInput.value) {\n this.updatePreview(root);\n }\n\n // Tab change handler - load iframe library when switching to iframe library tab\n const iframeLibraryTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabIframeLibraryBtn,\n );\n if (iframeLibraryTabBtn) {\n iframeLibraryTabBtn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n\n // Manually handle tab switching for Bootstrap 5\n this.switchToIframeLibraryTab(root);\n\n // Small delay to ensure tab pane is visible before loading iframe\n setTimeout(() => this.handleIframeLibraryTabClick(root), 100);\n });\n // Also handle Bootstrap tab events (if Bootstrap handles it)\n iframeLibraryTabBtn.addEventListener('shown.bs.tab', () =>\n this.handleIframeLibraryTabClick(root),\n );\n // jQuery Bootstrap 4 event\n const $iframeLibraryTabBtn = window.jQuery\n ? window.jQuery(iframeLibraryTabBtn)\n : null;\n if ($iframeLibraryTabBtn) {\n $iframeLibraryTabBtn.on('shown.bs.tab', () =>\n this.handleIframeLibraryTabClick(root),\n );\n }\n }\n\n // Tab change handler for URL tab\n const urlTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabUrlBtn,\n );\n if (urlTabBtn) {\n urlTabBtn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n\n // Manually handle tab switching\n this.switchToUrlTab(root);\n });\n }\n\n // Iframe library event listeners\n this.registerIframeLibraryEventListeners(root);\n\n // If editing, Configure tab is active - update preview immediately\n // If inserting, My Media tab is active - load the library\n if (this.isUpdating) {\n // When editing, Configure tab is already active, just update preview\n setTimeout(() => this.updatePreview(root), 100);\n } else {\n // When inserting, load My Media library tab\n setTimeout(() => this.handleIframeLibraryTabClick(root), 100);\n }\n }\n\n /**\n * Switch to the URL tab.\n *\n * @param {HTMLElement} root - Modal root element\n */\n switchToUrlTab(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n // Get tab buttons\n const urlTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabUrlBtn,\n );\n const urlTabItem = form.querySelector('.tiny_iframecms_tab_url_item');\n const iframeLibraryTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabIframeLibraryBtn,\n );\n\n // Get tab panes\n const urlPane = form.querySelector(Selectors.IFRAME.elements.paneUrl);\n const iframeLibraryPane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n // Show the Configure tab\n if (urlTabItem) {\n urlTabItem.style.display = '';\n }\n\n // Update tab button states\n if (urlTabBtn) {\n urlTabBtn.classList.add('active');\n urlTabBtn.setAttribute('aria-selected', 'true');\n }\n if (iframeLibraryTabBtn) {\n iframeLibraryTabBtn.classList.remove('active');\n iframeLibraryTabBtn.setAttribute('aria-selected', 'false');\n }\n\n // Update tab pane visibility\n if (urlPane) {\n urlPane.classList.add('show', 'active');\n }\n if (iframeLibraryPane) {\n iframeLibraryPane.classList.remove('show', 'active');\n }\n }\n\n /**\n * Switch to the iframe library tab.\n *\n * @param {HTMLElement} root - Modal root element\n */\n switchToIframeLibraryTab(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n // Get tab buttons\n const urlTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabUrlBtn,\n );\n const urlTabItem = form.querySelector('.tiny_iframecms_tab_url_item');\n const iframeLibraryTabBtn = form.querySelector(\n Selectors.IFRAME.elements.tabIframeLibraryBtn,\n );\n\n // Get tab panes\n const urlPane = form.querySelector(Selectors.IFRAME.elements.paneUrl);\n const iframeLibraryPane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n // Hide the Configure tab when switching to My Media\n if (urlTabItem) {\n urlTabItem.style.display = 'none';\n }\n\n // Update tab button states\n if (urlTabBtn) {\n urlTabBtn.classList.remove('active');\n urlTabBtn.setAttribute('aria-selected', 'false');\n }\n if (iframeLibraryTabBtn) {\n iframeLibraryTabBtn.classList.add('active');\n iframeLibraryTabBtn.setAttribute('aria-selected', 'true');\n }\n\n // Update tab pane visibility\n if (urlPane) {\n urlPane.classList.remove('show', 'active');\n }\n if (iframeLibraryPane) {\n iframeLibraryPane.classList.add('show', 'active');\n }\n }\n\n /**\n * Register event listeners for the iframe library.\n *\n * @param {HTMLElement} root - Modal root element\n */\n registerIframeLibraryEventListeners(root) {\n // Listen for messages from the iframe (for video selection)\n window.addEventListener('message', (event) => {\n this.handleIframeLibraryMessage(root, event);\n });\n }\n\n /**\n * Handle iframe library tab click - always refetch content (no caching).\n *\n * @param {HTMLElement} root - Modal root element\n */\n handleIframeLibraryTabClick(root) {\n // Always refetch content when tab is clicked (no caching)\n // Reset the loaded state to ensure fresh content is fetched\n this.iframeLibraryLoaded = false;\n this.loadIframeLibrary(root);\n }\n\n /**\n * Load the iframe library using LTI flow or fallback to static URL.\n *\n * @param {HTMLElement} root - Modal root element\n */\n loadIframeLibrary(root) {\n const ltiConfig = getLti(this.editor);\n // Check if LTI is configured with a content item URL\n if (ltiConfig?.contentItemUrl) {\n this.loadIframeLibraryViaLti(root);\n } else {\n // Fallback to static URL if LTI not configured\n this.loadIframeLibraryStatic(root);\n }\n }\n\n /**\n * Load the iframe library via LTI Deep Linking (Content Item Selection).\n * Sets the iframe src to contentitem.php which initiates the LTI Deep Linking flow.\n * This sends an LtiDeepLinkingRequest message, which will redirect to the\n * tool's content selection interface (e.g., /lti/select-media/).\n *\n * @param {HTMLElement} root - Modal root element\n */\n loadIframeLibraryViaLti(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const pane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n if (!pane) { return;\n }\n\n const placeholderEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryPlaceholder,\n );\n const loadingEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryLoading,\n );\n const iframeEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryFrame,\n );\n\n if (!iframeEl) { return;\n }\n\n // Hide placeholder, show loading state\n if (placeholderEl) {\n placeholderEl.classList.add('d-none');\n }\n if (loadingEl) {\n loadingEl.classList.remove('d-none');\n }\n iframeEl.classList.add('d-none');\n\n // Set up load listener - note: this may fire multiple times during LTI redirects\n const loadHandler = () => { this.handleIframeLibraryLoad(root);\n };\n iframeEl.addEventListener('load', loadHandler);\n\n // Set the iframe src to the content item URL\n // This initiates the LTI Deep Linking flow:\n // 1. contentitem.php initiates OIDC login\n // 2. LTI provider authenticates\n // 3. Moodle sends LtiDeepLinkingRequest\n // 4. Tool provider shows content selection interface\n const ltiConfig = getLti(this.editor);\n iframeEl.src = ltiConfig.contentItemUrl;\n }\n\n /**\n * Load the iframe library using static URL (fallback).\n *\n * @param {HTMLElement} root - Modal root element\n */\n loadIframeLibraryStatic(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const pane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n if (!pane) { return;\n }\n\n const placeholderEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryPlaceholder,\n );\n const loadingEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryLoading,\n );\n const iframeEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryFrame,\n );\n if (!iframeEl) { return;\n }\n\n // Hide placeholder, show loading state\n if (placeholderEl) {\n placeholderEl.classList.add('d-none');\n }\n if (loadingEl) {\n loadingEl.classList.remove('d-none');\n }\n iframeEl.classList.add('d-none');\n\n // Set up load listener before setting src\n const loadHandler = () => { // Only handle if the src matches our target URL\n if (iframeEl.src === this.iframeLibraryUrl) {\n this.handleIframeLibraryLoad(root);\n // Remove the listener after successful load\n iframeEl.removeEventListener('load', loadHandler);\n }\n };\n iframeEl.addEventListener('load', loadHandler);\n\n // Set the iframe source\n iframeEl.src = this.iframeLibraryUrl; }\n\n /**\n * Handle iframe library load event.\n *\n * @param {HTMLElement} root - Modal root element\n */\n handleIframeLibraryLoad(root) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n const pane = form.querySelector(\n Selectors.IFRAME.elements.paneIframeLibrary,\n );\n\n if (!pane) {\n return;\n }\n\n const placeholderEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryPlaceholder,\n );\n const loadingEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryLoading,\n );\n const iframeEl = pane.querySelector(\n Selectors.IFRAME.elements.iframeLibraryFrame,\n );\n\n // Hide placeholder and loading, show iframe\n if (placeholderEl) {\n placeholderEl.classList.add('d-none');\n }\n if (loadingEl) {\n loadingEl.classList.add('d-none');\n }\n if (iframeEl) {\n iframeEl.classList.remove('d-none');\n }\n\n this.iframeLibraryLoaded = true;\n }\n\n /**\n * Handle messages from the iframe library (for video selection).\n * Supports both custom videoSelected messages and LTI Deep Linking responses.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {MessageEvent} event - The message event\n */\n handleIframeLibraryMessage(root, event) {\n const data = event.data;\n\n if (!data) {\n return;\n }\n\n // Handle custom videoSelected message format\n if (data.type === 'videoSelected' && data.embedUrl) {\n this.selectIframeLibraryVideo(root, data.embedUrl, data.videoId);\n return;\n }\n\n // Handle LTI Deep Linking response format\n if (\n data.type === 'ltiDeepLinkingResponse' ||\n data.messageType === 'LtiDeepLinkingResponse'\n ) { const contentItems = data.content_items || data.contentItems || [];\n if (contentItems.length > 0) {\n const item = contentItems[0];\n // Extract embed URL from the content item\n const embedUrl =\n item.url || item.embed_url || item.embedUrl || '';\n const videoId = item.id || item.mediaId || '';\n if (embedUrl) { this.selectIframeLibraryVideo(root, embedUrl, videoId);\n }\n }\n return;\n }\n\n // Handle MediaCMS specific message format (if different from above)\n if (data.action === 'selectMedia' || data.action === 'mediaSelected') {\n const embedUrl = data.embedUrl || data.url || '';\n const videoId = data.mediaId || data.videoId || data.id || '';\n if (embedUrl) { this.selectIframeLibraryVideo(root, embedUrl, videoId);\n }\n return;\n }\n }\n\n /**\n * Select a video from the iframe library and populate the URL field.\n *\n * @param {HTMLElement} root - Modal root element\n * @param {string} embedUrl - The embed URL for the video\n * @param {string} videoId - The video ID\n */\n selectIframeLibraryVideo(root, embedUrl, videoId) {\n const form = root.querySelector(Selectors.IFRAME.elements.form);\n\n // Populate the URL field\n const urlInput = form.querySelector(Selectors.IFRAME.elements.url);\n urlInput.value = embedUrl;\n\n // Show the Configure tab (it starts hidden)\n const configureTabItem = root.querySelector('.tiny_iframecms_tab_url_item');\n if (configureTabItem) {\n configureTabItem.style.display = '';\n }\n\n // Switch to the Configure tab to show embed options\n this.switchToUrlTab(root);\n\n // Update the preview\n this.updatePreview(root);\n\n // Store the selected video\n this.selectedLibraryVideo = { embedUrl, videoId };\n }\n}\n"],"names":["constructor","editor","parseInput","input","trim","iframeMatch","match","this","parseEmbedUrl","startsWith","parseVideoUrl","url","urlObj","URL","baseUrl","protocol","host","pathname","searchParams","has","videoId","get","isEmbed","tParam","widthParam","heightParam","showTitle","linkTitle","showRelated","showUserAvatar","width","parseInt","height","startAt","secondsToTimeString","includes","rawUrl","isLtiLaunch","isGeneric","e","seconds","mins","Math","floor","secs","toString","padStart","timeStringToSeconds","timeStr","parts","split","isNaN","parseWidthHeight","value","parsed","buildEmbedUrl","options","set","startAtEnabled","data","editorData","autoConvertOptions","getDefault","key","fallback","_this","isUpdating","undefined","elementid","getElement","id","isupdating","textLinkOnly","is16_9","aspectRatio","is4_3","is1_1","isCustom","selectedIframe","getSelectedIframe","getCurrentIframeData","iframeLibraryLoaded","currentModal","IframeModal","create","title","component","templateContext","getTemplateContext","registerEventListeners","node","selection","getNode","nodeName","toLowerCase","getAttribute","iframe","querySelector","wrapper","closest","textLink","href","responsive","src","getFormValues","root","form","Selectors","IFRAME","elements","checked","values","viewUrl","linkText","str","div","document","createElement","textContent","innerHTML","escapeHtml","hrefUrl","replace","context","html","Templates","renderForPromise","updateUrlField","previewContainer","preview","urlWarning","classList","add","remove","embedUrl","previewWidth","min","scale","previewHeight","round","handleInputChange","clearTimeout","debounceTimer","setTimeout","updatePreview","handleAspectRatioChange","dimensions","aspectRatios","handleWidthChange","newWidth","heightInput","arr","x","y","calculatedHeight","handleHeightChange","newHeight","widthInput","calculatedWidth","modal","getRoot","generateIframeHtml","paragraphWrapper","outerHTML","getBody","querySelectorAll","forEach","p","fire","insertContent","confirmMessage","window","confirm","hide","$root","addEventListener","selector","target","on","ModalEvents","save","handleDialogueSubmission","hidden","destroy","removeBtn","actions","handleRemove","iframeLibraryTabBtn","tabIframeLibraryBtn","preventDefault","stopPropagation","switchToIframeLibraryTab","handleIframeLibraryTabClick","$iframeLibraryTabBtn","jQuery","urlTabBtn","tabUrlBtn","switchToUrlTab","registerIframeLibraryEventListeners","urlTabItem","urlPane","paneUrl","iframeLibraryPane","paneIframeLibrary","style","display","setAttribute","event","handleIframeLibraryMessage","loadIframeLibrary","ltiConfig","contentItemUrl","loadIframeLibraryViaLti","loadIframeLibraryStatic","pane","placeholderEl","iframeLibraryPlaceholder","loadingEl","iframeLibraryLoading","iframeEl","iframeLibraryFrame","handleIframeLibraryLoad","loadHandler","iframeLibraryUrl","removeEventListener","type","selectIframeLibraryVideo","messageType","action","mediaId","contentItems","content_items","length","item","embed_url","configureTabItem","selectedLibraryVideo"],"mappings":"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"} \ No newline at end of file diff --git a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/selectors.min.js b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/selectors.min.js index e8d66b3a..635f25e8 100755 --- a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/selectors.min.js +++ b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/selectors.min.js @@ -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",responsive:".tiny_iframecms_responsive",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",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",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",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})); //# sourceMappingURL=selectors.min.js.map \ No newline at end of file diff --git a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/selectors.min.js.map b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/selectors.min.js.map index 84c823ec..4190357e 100755 --- a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/selectors.min.js.map +++ b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/build/selectors.min.js.map @@ -1 +1 @@ -{"version":3,"file":"selectors.min.js","sources":["../src/selectors.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 plugin helper function to build queryable data selectors.\n *\n * @module tiny_mediacms/selectors\n * @copyright 2022 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n IMAGE: {\n actions: {\n submit: '.tiny_imagecms_urlentrysubmit',\n imageBrowser: '.openimagecmsbrowser',\n addUrl: '.tiny_imagecms_addurl',\n deleteImage: '.tiny_imagecms_deleteicon',\n },\n elements: {\n form: 'form.tiny_imagecms_form',\n alignSettings: '.tiny_imagecms_button',\n alt: '.tiny_imagecms_altentry',\n altWarning: '.tiny_imagecms_altwarning',\n height: '.tiny_imagecms_heightentry',\n width: '.tiny_imagecms_widthentry',\n url: '.tiny_imagecms_urlentry',\n urlWarning: '.tiny_imagecms_urlwarning',\n size: '.tiny_imagecms_size',\n presentation: '.tiny_imagecms_presentation',\n constrain: '.tiny_imagecms_constrain',\n customStyle: '.tiny_imagecms_customstyle',\n preview: '.tiny_imagecms_preview',\n previewBox: '.tiny_imagecms_preview_box',\n loaderIcon: '.tiny_imagecms_loader',\n loaderIconContainer: '.tiny_imagecms_loader_container',\n insertImage: '.tiny_imagecms_insert_image',\n modalFooter: '.modal-footer',\n dropzoneContainer: '.tiny_imagecms_dropzone_container',\n fileInput: '#tiny_imagecms_fileinput',\n fileNameLabel: '.tiny_imagecms_filename',\n sizeOriginal: '.tiny_imagecms_sizeoriginal',\n sizeCustom: '.tiny_imagecms_sizecustom',\n properties: '.tiny_imagecms_properties',\n },\n styles: {\n responsive: 'img-fluid',\n },\n },\n EMBED: {\n actions: {\n submit: '.tiny_mediacms_submit',\n mediaBrowser: '.openmediacmsbrowser',\n },\n elements: {\n form: 'form.tiny_mediacms_form',\n source: '.tiny_mediacms_source',\n track: '.tiny_mediacms_track',\n mediaSource: '.tiny_mediacms_media_source',\n linkSource: '.tiny_mediacms_link_source',\n linkSize: '.tiny_mediacms_link_size',\n posterSource: '.tiny_mediacms_poster_source',\n posterSize: '.tiny_mediacms_poster_size',\n displayOptions: '.tiny_mediacms_display_options',\n name: '.tiny_mediacms_name_entry',\n title: '.tiny_mediacms_title_entry',\n url: '.tiny_mediacms_url_entry',\n width: '.tiny_mediacms_width_entry',\n height: '.tiny_mediacms_height_entry',\n trackSource: '.tiny_mediacms_track_source',\n trackKind: '.tiny_mediacms_track_kind_entry',\n trackLabel: '.tiny_mediacms_track_label_entry',\n trackLang: '.tiny_mediacms_track_lang_entry',\n trackDefault: '.tiny_mediacms_track_default',\n mediaControl: '.tiny_mediacms_controls',\n mediaAutoplay: '.tiny_mediacms_autoplay',\n mediaMute: '.tiny_mediacms_mute',\n mediaLoop: '.tiny_mediacms_loop',\n advancedSettings: '.tiny_mediacms_advancedsettings',\n linkTab: 'li[data-medium-type=\"link\"]',\n videoTab: 'li[data-medium-type=\"video\"]',\n audioTab: 'li[data-medium-type=\"audio\"]',\n linkPane: '.tab-pane[data-medium-type=\"link\"]',\n videoPane: '.tab-pane[data-medium-type=\"video\"]',\n audioPane: '.tab-pane[data-medium-type=\"audio\"]',\n trackSubtitlesTab: 'li[data-track-kind=\"subtitles\"]',\n trackCaptionsTab: 'li[data-track-kind=\"captions\"]',\n trackDescriptionsTab: 'li[data-track-kind=\"descriptions\"]',\n trackChaptersTab: 'li[data-track-kind=\"chapters\"]',\n trackMetadataTab: 'li[data-track-kind=\"metadata\"]',\n trackSubtitlesPane: '.tab-pane[data-track-kind=\"subtitles\"]',\n trackCaptionsPane: '.tab-pane[data-track-kind=\"captions\"]',\n trackDescriptionsPane: '.tab-pane[data-track-kind=\"descriptions\"]',\n trackChaptersPane: '.tab-pane[data-track-kind=\"chapters\"]',\n trackMetadataPane: '.tab-pane[data-track-kind=\"metadata\"]',\n },\n mediaTypes: {\n link: 'LINK',\n video: 'VIDEO',\n audio: 'AUDIO',\n },\n trackKinds: {\n subtitles: 'SUBTITLES',\n captions: 'CAPTIONS',\n descriptions: 'DESCRIPTIONS',\n chapters: 'CHAPTERS',\n metadata: 'METADATA',\n },\n },\n IFRAME: {\n actions: {\n remove: '[data-action=\"remove\"]',\n },\n elements: {\n form: 'form.tiny_iframecms_form',\n url: '.tiny_iframecms_url',\n urlWarning: '.tiny_iframecms_url_warning',\n showTitle: '.tiny_iframecms_showtitle',\n linkTitle: '.tiny_iframecms_linktitle',\n showRelated: '.tiny_iframecms_showrelated',\n showUserAvatar: '.tiny_iframecms_showuseravatar',\n responsive: '.tiny_iframecms_responsive',\n textLinkOnly: '.tiny_iframecms_textlinkonly',\n startAt: '.tiny_iframecms_startat',\n startAtEnabled: '.tiny_iframecms_startat_enabled',\n aspectRatio: '.tiny_iframecms_aspectratio',\n width: '.tiny_iframecms_width',\n height: '.tiny_iframecms_height',\n preview: '.tiny_iframecms_preview',\n previewContainer: '.tiny_iframecms_preview_container',\n // Tab elements\n tabs: '.tiny_iframecms_tabs',\n tabUrlBtn: '.tiny_iframecms_tab_url_btn',\n tabIframeLibraryBtn: '.tiny_iframecms_tab_iframe_library_btn',\n paneUrl: '.tiny_iframecms_pane_url',\n paneIframeLibrary: '.tiny_iframecms_pane_iframe_library',\n // Iframe library elements\n iframeLibraryContainer: '.tiny_iframecms_iframe_library_container',\n iframeLibraryPlaceholder:\n '.tiny_iframecms_iframe_library_placeholder',\n iframeLibraryLoading: '.tiny_iframecms_iframe_library_loading',\n iframeLibraryFrame: '.tiny_iframecms_iframe_library_frame',\n },\n aspectRatios: {\n '16:9': { width: 560, height: 315 },\n '4:3': { width: 560, height: 420 },\n '1:1': { width: 400, height: 400 },\n custom: null,\n },\n },\n};\n"],"names":["IMAGE","actions","submit","imageBrowser","addUrl","deleteImage","elements","form","alignSettings","alt","altWarning","height","width","url","urlWarning","size","presentation","constrain","customStyle","preview","previewBox","loaderIcon","loaderIconContainer","insertImage","modalFooter","dropzoneContainer","fileInput","fileNameLabel","sizeOriginal","sizeCustom","properties","styles","responsive","EMBED","mediaBrowser","source","track","mediaSource","linkSource","linkSize","posterSource","posterSize","displayOptions","name","title","trackSource","trackKind","trackLabel","trackLang","trackDefault","mediaControl","mediaAutoplay","mediaMute","mediaLoop","advancedSettings","linkTab","videoTab","audioTab","linkPane","videoPane","audioPane","trackSubtitlesTab","trackCaptionsTab","trackDescriptionsTab","trackChaptersTab","trackMetadataTab","trackSubtitlesPane","trackCaptionsPane","trackDescriptionsPane","trackChaptersPane","trackMetadataPane","mediaTypes","link","video","audio","trackKinds","subtitles","captions","descriptions","chapters","metadata","IFRAME","remove","showTitle","linkTitle","showRelated","showUserAvatar","textLinkOnly","startAt","startAtEnabled","aspectRatio","previewContainer","tabs","tabUrlBtn","tabIframeLibraryBtn","paneUrl","paneIframeLibrary","iframeLibraryContainer","iframeLibraryPlaceholder","iframeLibraryLoading","iframeLibraryFrame","aspectRatios","custom"],"mappings":"yKAuBe,CACXA,MAAO,CACHC,QAAS,CACLC,OAAQ,gCACRC,aAAc,uBACdC,OAAQ,wBACRC,YAAa,6BAEjBC,SAAU,CACNC,KAAM,0BACNC,cAAe,wBACfC,IAAK,0BACLC,WAAY,4BACZC,OAAQ,6BACRC,MAAO,4BACPC,IAAK,0BACLC,WAAY,4BACZC,KAAM,sBACNC,aAAc,8BACdC,UAAW,2BACXC,YAAa,6BACbC,QAAS,yBACTC,WAAY,6BACZC,WAAY,wBACZC,oBAAqB,kCACrBC,YAAa,8BACbC,YAAa,gBACbC,kBAAmB,oCACnBC,UAAW,2BACXC,cAAe,0BACfC,aAAc,8BACdC,WAAY,4BACZC,WAAY,6BAEhBC,OAAQ,CACJC,WAAY,cAGpBC,MAAO,CACHhC,QAAS,CACLC,OAAQ,wBACRgC,aAAc,wBAElB5B,SAAU,CACNC,KAAM,0BACN4B,OAAQ,wBACRC,MAAO,uBACPC,YAAa,8BACbC,WAAY,6BACZC,SAAU,2BACVC,aAAc,+BACdC,WAAY,6BACZC,eAAgB,iCAChBC,KAAM,4BACNC,MAAO,6BACP/B,IAAK,2BACLD,MAAO,6BACPD,OAAQ,8BACRkC,YAAa,8BACbC,UAAW,kCACXC,WAAY,mCACZC,UAAW,kCACXC,aAAc,+BACdC,aAAc,0BACdC,cAAe,0BACfC,UAAW,sBACXC,UAAW,sBACXC,iBAAkB,kCAClBC,QAAS,8BACTC,SAAU,+BACVC,SAAU,+BACVC,SAAU,qCACVC,UAAW,sCACXC,UAAW,sCACXC,kBAAmB,kCACnBC,iBAAkB,iCAClBC,qBAAsB,qCACtBC,iBAAkB,iCAClBC,iBAAkB,iCAClBC,mBAAoB,yCACpBC,kBAAmB,wCACnBC,sBAAuB,4CACvBC,kBAAmB,wCACnBC,kBAAmB,yCAEvBC,WAAY,CACRC,KAAM,OACNC,MAAO,QACPC,MAAO,SAEXC,WAAY,CACRC,UAAW,YACXC,SAAU,WACVC,aAAc,eACdC,SAAU,WACVC,SAAU,aAGlBC,OAAQ,CACJhF,QAAS,CACLiF,OAAQ,0BAEZ5E,SAAU,CACNC,KAAM,2BACNM,IAAK,sBACLC,WAAY,8BACZqE,UAAW,4BACXC,UAAW,4BACXC,YAAa,8BACbC,eAAgB,iCAChBtD,WAAY,6BACZuD,aAAc,+BACdC,QAAS,0BACTC,eAAgB,kCAChBC,YAAa,8BACb9E,MAAO,wBACPD,OAAQ,yBACRQ,QAAS,0BACTwE,iBAAkB,oCAElBC,KAAM,uBACNC,UAAW,8BACXC,oBAAqB,yCACrBC,QAAS,2BACTC,kBAAmB,sCAEnBC,uBAAwB,2CACxBC,yBACI,6CACJC,qBAAsB,yCACtBC,mBAAoB,wCAExBC,aAAc,QACF,CAAEzF,MAAO,IAAKD,OAAQ,WACvB,CAAEC,MAAO,IAAKD,OAAQ,WACtB,CAAEC,MAAO,IAAKD,OAAQ,KAC7B2F,OAAQ"} \ No newline at end of file +{"version":3,"file":"selectors.min.js","sources":["../src/selectors.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 plugin helper function to build queryable data selectors.\n *\n * @module tiny_mediacms/selectors\n * @copyright 2022 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n IMAGE: {\n actions: {\n submit: '.tiny_imagecms_urlentrysubmit',\n imageBrowser: '.openimagecmsbrowser',\n addUrl: '.tiny_imagecms_addurl',\n deleteImage: '.tiny_imagecms_deleteicon',\n },\n elements: {\n form: 'form.tiny_imagecms_form',\n alignSettings: '.tiny_imagecms_button',\n alt: '.tiny_imagecms_altentry',\n altWarning: '.tiny_imagecms_altwarning',\n height: '.tiny_imagecms_heightentry',\n width: '.tiny_imagecms_widthentry',\n url: '.tiny_imagecms_urlentry',\n urlWarning: '.tiny_imagecms_urlwarning',\n size: '.tiny_imagecms_size',\n presentation: '.tiny_imagecms_presentation',\n constrain: '.tiny_imagecms_constrain',\n customStyle: '.tiny_imagecms_customstyle',\n preview: '.tiny_imagecms_preview',\n previewBox: '.tiny_imagecms_preview_box',\n loaderIcon: '.tiny_imagecms_loader',\n loaderIconContainer: '.tiny_imagecms_loader_container',\n insertImage: '.tiny_imagecms_insert_image',\n modalFooter: '.modal-footer',\n dropzoneContainer: '.tiny_imagecms_dropzone_container',\n fileInput: '#tiny_imagecms_fileinput',\n fileNameLabel: '.tiny_imagecms_filename',\n sizeOriginal: '.tiny_imagecms_sizeoriginal',\n sizeCustom: '.tiny_imagecms_sizecustom',\n properties: '.tiny_imagecms_properties',\n },\n styles: {\n responsive: 'img-fluid',\n },\n },\n EMBED: {\n actions: {\n submit: '.tiny_mediacms_submit',\n mediaBrowser: '.openmediacmsbrowser',\n },\n elements: {\n form: 'form.tiny_mediacms_form',\n source: '.tiny_mediacms_source',\n track: '.tiny_mediacms_track',\n mediaSource: '.tiny_mediacms_media_source',\n linkSource: '.tiny_mediacms_link_source',\n linkSize: '.tiny_mediacms_link_size',\n posterSource: '.tiny_mediacms_poster_source',\n posterSize: '.tiny_mediacms_poster_size',\n displayOptions: '.tiny_mediacms_display_options',\n name: '.tiny_mediacms_name_entry',\n title: '.tiny_mediacms_title_entry',\n url: '.tiny_mediacms_url_entry',\n width: '.tiny_mediacms_width_entry',\n height: '.tiny_mediacms_height_entry',\n trackSource: '.tiny_mediacms_track_source',\n trackKind: '.tiny_mediacms_track_kind_entry',\n trackLabel: '.tiny_mediacms_track_label_entry',\n trackLang: '.tiny_mediacms_track_lang_entry',\n trackDefault: '.tiny_mediacms_track_default',\n mediaControl: '.tiny_mediacms_controls',\n mediaAutoplay: '.tiny_mediacms_autoplay',\n mediaMute: '.tiny_mediacms_mute',\n mediaLoop: '.tiny_mediacms_loop',\n advancedSettings: '.tiny_mediacms_advancedsettings',\n linkTab: 'li[data-medium-type=\"link\"]',\n videoTab: 'li[data-medium-type=\"video\"]',\n audioTab: 'li[data-medium-type=\"audio\"]',\n linkPane: '.tab-pane[data-medium-type=\"link\"]',\n videoPane: '.tab-pane[data-medium-type=\"video\"]',\n audioPane: '.tab-pane[data-medium-type=\"audio\"]',\n trackSubtitlesTab: 'li[data-track-kind=\"subtitles\"]',\n trackCaptionsTab: 'li[data-track-kind=\"captions\"]',\n trackDescriptionsTab: 'li[data-track-kind=\"descriptions\"]',\n trackChaptersTab: 'li[data-track-kind=\"chapters\"]',\n trackMetadataTab: 'li[data-track-kind=\"metadata\"]',\n trackSubtitlesPane: '.tab-pane[data-track-kind=\"subtitles\"]',\n trackCaptionsPane: '.tab-pane[data-track-kind=\"captions\"]',\n trackDescriptionsPane: '.tab-pane[data-track-kind=\"descriptions\"]',\n trackChaptersPane: '.tab-pane[data-track-kind=\"chapters\"]',\n trackMetadataPane: '.tab-pane[data-track-kind=\"metadata\"]',\n },\n mediaTypes: {\n link: 'LINK',\n video: 'VIDEO',\n audio: 'AUDIO',\n },\n trackKinds: {\n subtitles: 'SUBTITLES',\n captions: 'CAPTIONS',\n descriptions: 'DESCRIPTIONS',\n chapters: 'CHAPTERS',\n metadata: 'METADATA',\n },\n },\n IFRAME: {\n actions: {\n remove: '[data-action=\"remove\"]',\n },\n elements: {\n form: 'form.tiny_iframecms_form',\n url: '.tiny_iframecms_url',\n urlWarning: '.tiny_iframecms_url_warning',\n showTitle: '.tiny_iframecms_showtitle',\n linkTitle: '.tiny_iframecms_linktitle',\n showRelated: '.tiny_iframecms_showrelated',\n showUserAvatar: '.tiny_iframecms_showuseravatar',\n textLinkOnly: '.tiny_iframecms_textlinkonly',\n startAt: '.tiny_iframecms_startat',\n startAtEnabled: '.tiny_iframecms_startat_enabled',\n aspectRatio: '.tiny_iframecms_aspectratio',\n width: '.tiny_iframecms_width',\n height: '.tiny_iframecms_height',\n preview: '.tiny_iframecms_preview',\n previewContainer: '.tiny_iframecms_preview_container',\n // Tab elements\n tabs: '.tiny_iframecms_tabs',\n tabUrlBtn: '.tiny_iframecms_tab_url_btn',\n tabIframeLibraryBtn: '.tiny_iframecms_tab_iframe_library_btn',\n paneUrl: '.tiny_iframecms_pane_url',\n paneIframeLibrary: '.tiny_iframecms_pane_iframe_library',\n // Iframe library elements\n iframeLibraryContainer: '.tiny_iframecms_iframe_library_container',\n iframeLibraryPlaceholder:\n '.tiny_iframecms_iframe_library_placeholder',\n iframeLibraryLoading: '.tiny_iframecms_iframe_library_loading',\n iframeLibraryFrame: '.tiny_iframecms_iframe_library_frame',\n },\n aspectRatios: {\n '16:9': { width: 560, height: 315 },\n '4:3': { width: 560, height: 420 },\n '1:1': { width: 400, height: 400 },\n custom: null,\n },\n },\n};\n"],"names":["IMAGE","actions","submit","imageBrowser","addUrl","deleteImage","elements","form","alignSettings","alt","altWarning","height","width","url","urlWarning","size","presentation","constrain","customStyle","preview","previewBox","loaderIcon","loaderIconContainer","insertImage","modalFooter","dropzoneContainer","fileInput","fileNameLabel","sizeOriginal","sizeCustom","properties","styles","responsive","EMBED","mediaBrowser","source","track","mediaSource","linkSource","linkSize","posterSource","posterSize","displayOptions","name","title","trackSource","trackKind","trackLabel","trackLang","trackDefault","mediaControl","mediaAutoplay","mediaMute","mediaLoop","advancedSettings","linkTab","videoTab","audioTab","linkPane","videoPane","audioPane","trackSubtitlesTab","trackCaptionsTab","trackDescriptionsTab","trackChaptersTab","trackMetadataTab","trackSubtitlesPane","trackCaptionsPane","trackDescriptionsPane","trackChaptersPane","trackMetadataPane","mediaTypes","link","video","audio","trackKinds","subtitles","captions","descriptions","chapters","metadata","IFRAME","remove","showTitle","linkTitle","showRelated","showUserAvatar","textLinkOnly","startAt","startAtEnabled","aspectRatio","previewContainer","tabs","tabUrlBtn","tabIframeLibraryBtn","paneUrl","paneIframeLibrary","iframeLibraryContainer","iframeLibraryPlaceholder","iframeLibraryLoading","iframeLibraryFrame","aspectRatios","custom"],"mappings":"yKAuBe,CACXA,MAAO,CACHC,QAAS,CACLC,OAAQ,gCACRC,aAAc,uBACdC,OAAQ,wBACRC,YAAa,6BAEjBC,SAAU,CACNC,KAAM,0BACNC,cAAe,wBACfC,IAAK,0BACLC,WAAY,4BACZC,OAAQ,6BACRC,MAAO,4BACPC,IAAK,0BACLC,WAAY,4BACZC,KAAM,sBACNC,aAAc,8BACdC,UAAW,2BACXC,YAAa,6BACbC,QAAS,yBACTC,WAAY,6BACZC,WAAY,wBACZC,oBAAqB,kCACrBC,YAAa,8BACbC,YAAa,gBACbC,kBAAmB,oCACnBC,UAAW,2BACXC,cAAe,0BACfC,aAAc,8BACdC,WAAY,4BACZC,WAAY,6BAEhBC,OAAQ,CACJC,WAAY,cAGpBC,MAAO,CACHhC,QAAS,CACLC,OAAQ,wBACRgC,aAAc,wBAElB5B,SAAU,CACNC,KAAM,0BACN4B,OAAQ,wBACRC,MAAO,uBACPC,YAAa,8BACbC,WAAY,6BACZC,SAAU,2BACVC,aAAc,+BACdC,WAAY,6BACZC,eAAgB,iCAChBC,KAAM,4BACNC,MAAO,6BACP/B,IAAK,2BACLD,MAAO,6BACPD,OAAQ,8BACRkC,YAAa,8BACbC,UAAW,kCACXC,WAAY,mCACZC,UAAW,kCACXC,aAAc,+BACdC,aAAc,0BACdC,cAAe,0BACfC,UAAW,sBACXC,UAAW,sBACXC,iBAAkB,kCAClBC,QAAS,8BACTC,SAAU,+BACVC,SAAU,+BACVC,SAAU,qCACVC,UAAW,sCACXC,UAAW,sCACXC,kBAAmB,kCACnBC,iBAAkB,iCAClBC,qBAAsB,qCACtBC,iBAAkB,iCAClBC,iBAAkB,iCAClBC,mBAAoB,yCACpBC,kBAAmB,wCACnBC,sBAAuB,4CACvBC,kBAAmB,wCACnBC,kBAAmB,yCAEvBC,WAAY,CACRC,KAAM,OACNC,MAAO,QACPC,MAAO,SAEXC,WAAY,CACRC,UAAW,YACXC,SAAU,WACVC,aAAc,eACdC,SAAU,WACVC,SAAU,aAGlBC,OAAQ,CACJhF,QAAS,CACLiF,OAAQ,0BAEZ5E,SAAU,CACNC,KAAM,2BACNM,IAAK,sBACLC,WAAY,8BACZqE,UAAW,4BACXC,UAAW,4BACXC,YAAa,8BACbC,eAAgB,iCAChBC,aAAc,+BACdC,QAAS,0BACTC,eAAgB,kCAChBC,YAAa,8BACb9E,MAAO,wBACPD,OAAQ,yBACRQ,QAAS,0BACTwE,iBAAkB,oCAElBC,KAAM,uBACNC,UAAW,8BACXC,oBAAqB,yCACrBC,QAAS,2BACTC,kBAAmB,sCAEnBC,uBAAwB,2CACxBC,yBACI,6CACJC,qBAAsB,yCACtBC,mBAAoB,wCAExBC,aAAc,QACF,CAAEzF,MAAO,IAAKD,OAAQ,WACvB,CAAEC,MAAO,IAAKD,OAAQ,WACtB,CAAEC,MAAO,IAAKD,OAAQ,KAC7B2F,OAAQ"} \ No newline at end of file diff --git a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/src/iframeembed.js b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/src/iframeembed.js index 96ae5a71..59ed5314 100755 --- a/lms-plugins/mediacms-moodle/tiny/mediacms/amd/src/iframeembed.js +++ b/lms-plugins/mediacms-moodle/tiny/mediacms/amd/src/iframeembed.js @@ -188,20 +188,16 @@ export default class IframeEmbed { } /** - * Parse width/height value - handle both numeric and '100%'. + * Parse width/height value. * * @param {string} value - Width or height value - * @returns {number|string|null} Parsed value + * @returns {number|null} Parsed value */ parseWidthHeight(value) { if (!value) { return null; } - const trimmed = value.trim(); - if (trimmed === '100%') { - return '100%'; - } - const parsed = parseInt(trimmed); + const parsed = parseInt(value.trim()); return isNaN(parsed) ? null : parsed; } @@ -229,12 +225,11 @@ export default class IframeEmbed { ); url.searchParams.set('linkTitle', options.linkTitle ? '1' : '0'); - // Add width and height ONLY if responsive is disabled and values are not 100% - // When responsive is enabled, dimensions are set to 100% but not included in URL - if (!options.responsive && options.width && options.width !== '100%') { + // Add width and height if provided + if (options.width) { url.searchParams.set('width', options.width.toString()); } - if (!options.responsive && options.height && options.height !== '100%') { + if (options.height) { url.searchParams.set('height', options.height.toString()); } @@ -271,17 +266,19 @@ export default class IframeEmbed { : fallback; }; - // Determine responsive mode: - // - If editing with 100% dimensions, responsive is ON - // - If editing with numeric dimensions, responsive is OFF - // - Otherwise, default to responsive=ON for new embeds - let isResponsive; + // Determine dimensions: + // - For editing: preserve existing dimensions + // - For new embeds: default to 640x360 + let width, height; + if (this.isUpdating && (data.width || data.height)) { - // Check if dimensions are 100% (responsive) or numeric (fixed) - isResponsive = data.width === '100%' || data.height === '100%'; + // Editing: preserve existing dimensions + width = data.width || 640; + height = data.height || 360; } else { - // New embed or no dimensions: responsive defaults to ON - isResponsive = data.responsive !== false; + // New embed: default to 640x360 (16:9 aspect ratio) + width = 640; + height = 360; } return { @@ -292,13 +289,11 @@ export default class IframeEmbed { linkTitle: getDefault('linkTitle'), showRelated: getDefault('showRelated'), showUserAvatar: getDefault('showUserAvatar'), - responsive: isResponsive, textLinkOnly: data.textLinkOnly || false, startAtEnabled: data.startAtEnabled || false, startAt: data.startAt || '0:00', - // No default dimensions - only use provided values - width: data.width || '', - height: data.height || '', + width: width, + height: height, is16_9: !data.aspectRatio || data.aspectRatio === '16:9', is4_3: data.aspectRatio === '4:3', is1_1: data.aspectRatio === '1:1', @@ -404,21 +399,9 @@ export default class IframeEmbed { let width = parsed?.width || this.selectedIframe.getAttribute('width') || null; let height = parsed?.height || this.selectedIframe.getAttribute('height') || null; - // Check if responsive: either by style (aspect-ratio) or by 100% dimensions - const style = this.selectedIframe.getAttribute('style') || ''; - const hasAspectRatio = style.includes('aspect-ratio'); - const has100Percent = width === '100%' || height === '100%'; - const isResponsive = hasAspectRatio || has100Percent; - - // If responsive, set both to 100% - if (isResponsive) { - width = '100%'; - height = '100%'; - } else { - // Parse numeric values - width = width ? parseInt(width) : null; - height = height ? parseInt(height) : null; - } + // Parse numeric values + width = width ? parseInt(width) : null; + height = height ? parseInt(height) : null; return { url: src, @@ -428,7 +411,6 @@ export default class IframeEmbed { linkTitle: parsed?.linkTitle ?? true, showRelated: parsed?.showRelated ?? true, showUserAvatar: parsed?.showUserAvatar ?? true, - responsive: isResponsive, startAtEnabled: parsed?.startAt !== null, startAt: parsed?.startAt || '0:00', }; @@ -455,8 +437,6 @@ export default class IframeEmbed { showUserAvatar: form.querySelector( Selectors.IFRAME.elements.showUserAvatar, ).checked, - responsive: form.querySelector(Selectors.IFRAME.elements.responsive) - .checked, textLinkOnly: form.querySelector(Selectors.IFRAME.elements.textLinkOnly) .checked, startAtEnabled: form.querySelector( @@ -519,21 +499,10 @@ export default class IframeEmbed { const embedUrl = this.buildEmbedUrl(parsed, values); - // Calculate aspect ratio values for CSS - const aspectRatioCalcs = { - '16:9': '16 / 9', - '4:3': '4 / 3', - '1:1': '1 / 1', - custom: `${values.width} / ${values.height}`, - }; - const context = { src: embedUrl, width: values.width, height: values.height, - responsive: values.responsive, - aspectRatioCalc: aspectRatioCalcs[values.aspectRatio] || '16 / 9', - aspectRatioValue: aspectRatioCalcs[values.aspectRatio] || '16 / 9', }; const { html } = await Templates.renderForPromise( @@ -610,25 +579,10 @@ export default class IframeEmbed { `; } else { - // Show a scaled preview - let previewWidth, previewHeight; - - if (values.responsive || values.width === '100%' || values.height === '100%') { - // For responsive, use default preview dimensions with aspect ratio - const aspectRatioCalcs = { - '16:9': { width: 400, height: 225 }, - '4:3': { width: 400, height: 300 }, - '1:1': { width: 300, height: 300 }, - }; - const defaultDims = aspectRatioCalcs[values.aspectRatio] || { width: 400, height: 225 }; - previewWidth = defaultDims.width; - previewHeight = defaultDims.height; - } else { - // For fixed dimensions, scale to fit preview - previewWidth = Math.min(values.width, 400); - const scale = previewWidth / values.width; - previewHeight = Math.round(values.height * scale); - } + // Show a scaled preview - scale to fit preview area + const previewWidth = Math.min(values.width, 400); + const scale = previewWidth / values.width; + const previewHeight = Math.round(values.height * scale); previewContainer.innerHTML = ` -{{/responsive}} -{{^responsive}} -{{/responsive}}