diff --git a/lib/editor/tiny/plugins/media/amd/build/embed/embedhandler.min.js b/lib/editor/tiny/plugins/media/amd/build/embed/embedhandler.min.js index 17761bd3cb9..fcf1c5fc194 100644 --- a/lib/editor/tiny/plugins/media/amd/build/embed/embedhandler.min.js +++ b/lib/editor/tiny/plugins/media/amd/build/embed/embedhandler.min.js @@ -1,3 +1,3 @@ -define("tiny_media/embed/embedhandler",["exports","../selectors","./embedinsert","../helpers","core/modal_events","editor_tiny/utils","./embedhelpers","core/templates","./embedthumbnailinsert"],(function(_exports,_selectors,_embedinsert,_helpers,ModalEvents,_utils,_embedhelpers,_templates,_embedthumbnailinsert){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.EmbedHandler=void 0,_selectors=_interopRequireDefault(_selectors),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),_templates=_interopRequireDefault(_templates);_exports.EmbedHandler=class{constructor(_data){var _this=this;_defineProperty(this,"loadTemplatePromise",(templateContext=>{templateContext.elementid=this.editor.id,templateContext.bodyTemplate=_selectors.default.EMBED.template.body.insertMediaBody,templateContext.footerTemplate=_selectors.default.EMBED.template.footer.insertMediaFooter,templateContext.selector=_selectors.default.EMBED.type,Promise.all([(0,_helpers.body)(templateContext,this.root),(0,_helpers.footer)(templateContext,this.root)]).then((()=>{new _embedinsert.EmbedInsert(this).init()})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"loadInsertThumbnailTemplatePromise",(async(templateContext,root,mediaData)=>{Promise.all([(0,_helpers.body)(templateContext,root.root),(0,_helpers.footer)(templateContext,root.root)]).then((()=>{this.currentModal.insertMediaModal||(this.currentModal.insertMediaModal=this.currentModal),root.uploadThumbnailModal&&(this.currentModal.uploadThumbnailModal=root.uploadThumbnailModal),this.thumbnailModalRoot=root.root,new _embedthumbnailinsert.EmbedThumbnailInsert(this).init(mediaData)})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"loadMediaDetails",(async(embedPreview,templateContext)=>{Promise.all([(0,_helpers.body)(templateContext,this.root),(0,_helpers.footer)(templateContext,this.root)]).then((()=>{embedPreview.init()})).catch((error=>{(0,_helpers.stopMediaLoading)(this.root,_selectors.default.EMBED.type),window.console.log(error)}))})),_defineProperty(this,"resetUploadForm",(function(){let isMediaInsert=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];isMediaInsert?(_this.newMediaLink=!1,_this.fetchedMediaLinkTitle=null,_this.resetCurrentMediaData(),_this.loadTemplatePromise((0,_embedhelpers.insertMediaTemplateContext)(_this))):_this.loadInsertThumbnailTemplatePromise((0,_embedhelpers.insertMediaThumbnailTemplateContext)(_this),{root:_this.thumbnailModalRoot},_this.mediaData)})),_defineProperty(this,"getMediaProperties",(()=>{var _media$getAttribute;const media=this.selectedMedia;if(!media)return null;const tracks={subtitles:[],captions:[],descriptions:[],chapters:[],metadata:[]},sources=[];media.querySelectorAll("track").forEach((track=>{tracks[track.getAttribute("kind")].push({src:track.getAttribute("src"),srclang:track.getAttribute("srclang"),label:track.getAttribute("label"),defaultTrack:(0,_embedhelpers.hasAudioVideoAttr)(track,"default")})})),media.querySelectorAll("source").forEach((source=>{sources.push(source.src)}));const title=null!==(_media$getAttribute=media.getAttribute("title"))&&void 0!==_media$getAttribute?_media$getAttribute:media.textContent;return{type:this.mediaType,sources:sources,poster:media.getAttribute("poster"),title:!!title&&title.trim(),width:media.getAttribute("width"),height:media.getAttribute("height"),autoplay:(0,_embedhelpers.hasAudioVideoAttr)(media,"autoplay"),loop:(0,_embedhelpers.hasAudioVideoAttr)(media,"loop"),muted:(0,_embedhelpers.hasAudioVideoAttr)(media,"muted"),controls:(0,_embedhelpers.hasAudioVideoAttr)(media,"controls"),tracks:tracks}})),_defineProperty(this,"getCurrentEmbedData",(()=>{const properties=this.getMediaProperties();if(!properties||this.newMediaLink)return{media:{}};const processedProperties={};return processedProperties.media=properties,processedProperties.link=!1,processedProperties})),_defineProperty(this,"getHelpStrings",(async()=>(this.helpStrings||(this.helpStrings=await(0,_embedhelpers.getHelpStrings)()),this.helpStrings))),_defineProperty(this,"getTemplateContext",(async data=>{const languages=(0,_embedhelpers.prepareMoodleLang)(this.editor),helpIcons=Array.from(Object.entries(await this.getHelpStrings())).forEach((_ref=>{let[key,text]=_ref;data["".concat(key.toLowerCase(),"helpicon")]={text:text}}));return Object.assign({},{elementid:this.editor.getElement().id,showFilePickerTrack:this.canShowFilePickerTrack,langsInstalled:languages.installed,langsAvailable:languages.available,media:!0,isUpdating:this.isUpdating},data,helpIcons)})),_defineProperty(this,"getMediaTemplateContext",(async function(){let data=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return data?data.hasOwnProperty("isUpdating")?_this.isUpdating=data.isUpdating:_this.isUpdating=Object.keys(data).length>1:data=Object.assign({},_this.getCurrentEmbedData()),await _this.getTemplateContext(data)})),_defineProperty(this,"loadMediaPreview",(url=>{new _embedinsert.EmbedInsert(this).loadMediaPreview(url)})),_defineProperty(this,"resetCurrentMediaData",(()=>{this.media={},this.mediaType=null,this.selectedMedia=null})),_defineProperty(this,"getFilePickerTypeFromElement",(element=>element.closest(_selectors.default.EMBED.elements.posterSource)?"image":element.closest(_selectors.default.EMBED.elements.trackSource)?"subtitle":"media")),_defineProperty(this,"getTrackTypeFromTabPane",(tabPane=>tabPane.getAttribute("data-track-kind"))),_defineProperty(this,"clickHandler",(async e=>{const element=e.target;if(element.closest(_selectors.default.EMBED.actions.mediaBrowser)){e.preventDefault();const fpType=this.getFilePickerTypeFromElement(element),params=await(0,_utils.displayFilepicker)(this.editor,fpType);this.trackFilePickerCallback(params,element,fpType)}e.target.closest(_selectors.default.EMBED.actions.addUrl)&&((0,_helpers.startMediaLoading)(this.root,_selectors.default.EMBED.type),this.urlChanged());element.closest(_selectors.default.EMBED.elements.track+" .addcomponent")&&(e.preventDefault(),this.addTrackComponent(element));element.closest(_selectors.default.EMBED.elements.track+" .removecomponent")&&(e.preventDefault(),this.removeTrackComponent(element));const trackDefaultAction=element.closest(_selectors.default.EMBED.elements.trackDefault);if(trackDefaultAction&&trackDefaultAction.checked){const getKind=el=>this.getTrackTypeFromTabPane(el.parentElement.closest(".tab-pane"));element.parentElement.closest(".tab-content").querySelectorAll(_selectors.default.EMBED.elements.trackDefault).forEach((select=>{select!==element&&getKind(element)===getKind(select)&&(select.checked=!1)}))}})),_defineProperty(this,"getMediaHTML",(form=>{this.mediaType=this.root.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer).dataset.mediaType;const tabContent=form.querySelector(".tab-content");return this["getMediaHTML"+this.mediaType[0].toUpperCase()+this.mediaType.substr(1)](tabContent)})),_defineProperty(this,"getMediaHTMLVideo",(tab=>{const details=document.querySelector(_selectors.default.EMBED.elements.mediaDetailsBody),context=this.getContextForMediaHTML(tab,details);context.width=details.querySelector(_selectors.default.EMBED.elements.width).value||!1,context.height=details.querySelector(_selectors.default.EMBED.elements.height).value||!1;const mediaPreviewContainer=details.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer);return context.poster=mediaPreviewContainer.dataset.mediaPoster||!1,context.sources?_templates.default.renderForPromise("tiny_media/embed/embed_media_video",context):""})),_defineProperty(this,"getMediaHTMLAudio",(tab=>{const details=document.querySelector(_selectors.default.EMBED.elements.mediaDetailsBody),context=this.getContextForMediaHTML(tab,details);return context.sources.length?_templates.default.renderForPromise("tiny_media/embed/embed_media_audio",context):""})),_defineProperty(this,"getContextForMediaHTML",((tab,details)=>{var _mediaPreviewContaine;const tracks=Array.from(tab.querySelectorAll(_selectors.default.EMBED.elements.track)).map((track=>({track:track.querySelector(_selectors.default.EMBED.elements.trackSource+" "+_selectors.default.EMBED.elements.url).value,kind:this.getTrackTypeFromTabPane(track.closest(".tab-pane")),label:track.querySelector(_selectors.default.EMBED.elements.trackLabel).value||track.querySelector(_selectors.default.EMBED.elements.trackLang).value,srclang:track.querySelector(_selectors.default.EMBED.elements.trackLang).value,defaultTrack:track.querySelector(_selectors.default.EMBED.elements.trackDefault).checked?"true":null}))).filter((track=>!!track.track)),mediaPreviewContainer=details.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer);let sources=null!==(_mediaPreviewContaine=mediaPreviewContainer.dataset.originalUrl)&&void 0!==_mediaPreviewContaine?_mediaPreviewContaine:null;this.alternativeSources&&(this.alternativeSources[0]=sources,sources=this.alternativeSources);const title=details.querySelector(_selectors.default.EMBED.elements.title).value;mediaPreviewContainer.removeAttribute("data-original-url");const templateContext={sources:sources,tracks:tracks,showControls:details.querySelector(_selectors.default.EMBED.elements.mediaControl).checked,autoplay:details.querySelector(_selectors.default.EMBED.elements.mediaAutoplay).checked,muted:details.querySelector(_selectors.default.EMBED.elements.mediaMute).checked,loop:details.querySelector(_selectors.default.EMBED.elements.mediaLoop).checked,title:""!==title&&title.trim()};return"link"===this.mediaType&&(templateContext.description=Array.isArray(sources)?sources[0]:sources),templateContext})),_defineProperty(this,"handleDialogueSubmission",(async(event,modal)=>{const{html:html}=await this.getMediaHTML(modal.getRoot()[0]);html&&(this.isUpdating?(this.selectedMedia.outerHTML=html,this.isUpdating=!1):this.editor.insertContent(html))})),_defineProperty(this,"registerEventListeners",(async()=>{this.canShowFilePickerTrack&&this.root.addEventListener("click",this.clickHandler.bind(this)),this.root.addEventListener("input",(e=>{const urlEle=e.target.closest(_selectors.default.EMBED.elements.fromUrl);urlEle&&this.toggleUrlButton(urlEle,this.root)})),this.modalRoot.on(ModalEvents.hidden,(()=>{this.currentModal.destroy()})),this.modalRoot.on(ModalEvents.save,this.handleDialogueSubmission.bind(this))})),(0,_helpers.setPropertiesFromData)(this,_data)}urlChanged(){const url=this.root.querySelector(_selectors.default.EMBED.elements.fromUrl).value;url&&url!==this.currentUrl&&(this.mediaType=null,this.newMediaLink=!0,this.loadMediaPreview(url))}trackFilePickerCallback(params,element,fpType){if(""!==params.url){if(element.closest(".tab-pane")){if(element.closest(_selectors.default.EMBED.elements.source).querySelector(_selectors.default.EMBED.elements.url).value=params.url,"subtitle"===fpType){const subtitleLang=params.file.split(".vtt")[0].split("-").slice(-1)[0],langObj=(0,_embedhelpers.getMoodleLangObj)(subtitleLang,this.editor);if(langObj){const track=element.closest(_selectors.default.EMBED.elements.track);track.querySelector(_selectors.default.EMBED.elements.trackLabel).value=langObj.lang.trim(),track.querySelector(_selectors.default.EMBED.elements.trackLang).value=langObj.code}}}else this.newFileUpload=!0,this.resetCurrentMediaData(),this.loadMediaPreview(params.url)}}addTrackComponent(element){const trackElement=element.closest(_selectors.default.EMBED.elements.track),clone=trackElement.cloneNode(!0);trackElement.querySelector(".removecomponent-wrapper").classList.remove("hidden"),trackElement.querySelector(".addcomponent-wrapper").classList.add("hidden"),trackElement.parentNode.insertBefore(clone,trackElement.nextSibling)}removeTrackComponent(element){element.closest(_selectors.default.EMBED.elements.track).remove()}toggleUrlButton(input,root){const url=input.value;root.querySelector(_selectors.default.EMBED.actions.addUrl).disabled=!(""!==url&&(0,_helpers.isValidUrl)(url))}getMediaHTMLLink(){var _document$querySelect;const mediaPreviewContainer=document.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer),context={name:null!==(_document$querySelect=document.querySelector(_selectors.default.EMBED.elements.title).value)&&void 0!==_document$querySelect?_document$querySelect:mediaPreviewContainer.dataset.originalUrl,url:mediaPreviewContainer.dataset.originalUrl||!1};return context.url?_templates.default.renderForPromise("tiny_media/embed/embed_media_link",context):""}}})); +define("tiny_media/embed/embedhandler",["exports","../selectors","./embedinsert","../helpers","core/modal_events","editor_tiny/utils","./embedhelpers","core/templates","./embedthumbnailinsert"],(function(_exports,_selectors,_embedinsert,_helpers,ModalEvents,_utils,_embedhelpers,_templates,_embedthumbnailinsert){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.EmbedHandler=void 0,_selectors=_interopRequireDefault(_selectors),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),_templates=_interopRequireDefault(_templates);_exports.EmbedHandler=class{constructor(_data){var _this=this;_defineProperty(this,"loadTemplatePromise",(templateContext=>{templateContext.elementid=this.editor.id,templateContext.bodyTemplate=_selectors.default.EMBED.template.body.insertMediaBody,templateContext.footerTemplate=_selectors.default.EMBED.template.footer.insertMediaFooter,templateContext.selector=_selectors.default.EMBED.type,Promise.all([(0,_helpers.body)(templateContext,this.root),(0,_helpers.footer)(templateContext,this.root)]).then((()=>{new _embedinsert.EmbedInsert(this).init()})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"loadInsertThumbnailTemplatePromise",(async(templateContext,root,mediaData)=>{Promise.all([(0,_helpers.body)(templateContext,root.root),(0,_helpers.footer)(templateContext,root.root)]).then((()=>{this.currentModal.insertMediaModal||(this.currentModal.insertMediaModal=this.currentModal),root.uploadThumbnailModal&&(this.currentModal.uploadThumbnailModal=root.uploadThumbnailModal),this.thumbnailModalRoot=root.root,new _embedthumbnailinsert.EmbedThumbnailInsert(this).init(mediaData)})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"loadMediaDetails",(async(embedPreview,templateContext)=>{Promise.all([(0,_helpers.body)(templateContext,this.root),(0,_helpers.footer)(templateContext,this.root)]).then((()=>{embedPreview.init()})).catch((error=>{(0,_helpers.stopMediaLoading)(this.root,_selectors.default.EMBED.type),window.console.log(error)}))})),_defineProperty(this,"resetUploadForm",(function(){let isMediaInsert=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];isMediaInsert?(_this.newMediaLink=!1,_this.fetchedMediaLinkTitle=null,_this.resetCurrentMediaData(),_this.loadTemplatePromise((0,_embedhelpers.insertMediaTemplateContext)(_this))):_this.loadInsertThumbnailTemplatePromise((0,_embedhelpers.insertMediaThumbnailTemplateContext)(_this),{root:_this.thumbnailModalRoot},_this.mediaData)})),_defineProperty(this,"getMediaProperties",(()=>{var _media$getAttribute;const media=this.selectedMedia;if(!media)return null;const tracks={subtitles:[],captions:[],descriptions:[],chapters:[],metadata:[]},sources=[];media.querySelectorAll("track").forEach((track=>{tracks[track.getAttribute("kind")].push({src:track.getAttribute("src"),srclang:track.getAttribute("srclang"),label:track.getAttribute("label"),defaultTrack:(0,_embedhelpers.hasAudioVideoAttr)(track,"default")})})),media.querySelectorAll("source").forEach((source=>{sources.push(source.src)}));const title=null!==(_media$getAttribute=media.getAttribute("title"))&&void 0!==_media$getAttribute?_media$getAttribute:media.textContent;return{type:this.mediaType,sources:sources,poster:media.getAttribute("poster"),title:!!title&&title.trim(),width:media.getAttribute("width"),height:media.getAttribute("height"),autoplay:(0,_embedhelpers.hasAudioVideoAttr)(media,"autoplay"),loop:(0,_embedhelpers.hasAudioVideoAttr)(media,"loop"),muted:(0,_embedhelpers.hasAudioVideoAttr)(media,"muted"),controls:(0,_embedhelpers.hasAudioVideoAttr)(media,"controls"),tracks:tracks}})),_defineProperty(this,"getCurrentEmbedData",(()=>{const properties=this.getMediaProperties();if(!properties||this.newMediaLink)return{media:{}};const processedProperties={};return processedProperties.media=properties,processedProperties.link=!1,processedProperties})),_defineProperty(this,"getHelpStrings",(async()=>(this.helpStrings||(this.helpStrings=await(0,_embedhelpers.getHelpStrings)()),this.helpStrings))),_defineProperty(this,"getTemplateContext",(async data=>{const languages=(0,_embedhelpers.prepareMoodleLang)(this.editor),helpIcons=Array.from(Object.entries(await this.getHelpStrings())).forEach((_ref=>{let[key,text]=_ref;data["".concat(key.toLowerCase(),"helpicon")]={text:text}}));return Object.assign({},{elementid:this.editor.getElement().id,showFilePickerTrack:this.canShowFilePickerTrack,langsInstalled:languages.installed,langsAvailable:languages.available,media:!0,isUpdating:this.isUpdating},data,helpIcons)})),_defineProperty(this,"getMediaTemplateContext",(async function(){let data=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return data?data.hasOwnProperty("isUpdating")?_this.isUpdating=data.isUpdating:_this.isUpdating=Object.keys(data).length>1:data=Object.assign({},_this.getCurrentEmbedData()),await _this.getTemplateContext(data)})),_defineProperty(this,"loadMediaPreview",(url=>{new _embedinsert.EmbedInsert(this).loadMediaPreview(url)})),_defineProperty(this,"resetCurrentMediaData",(()=>{this.media={},this.mediaType=null,this.selectedMedia=null})),_defineProperty(this,"getFilePickerTypeFromElement",(element=>element.closest(_selectors.default.EMBED.elements.posterSource)?"image":element.closest(_selectors.default.EMBED.elements.trackSource)?"subtitle":"media")),_defineProperty(this,"getTrackTypeFromTabPane",(tabPane=>tabPane.getAttribute("data-track-kind"))),_defineProperty(this,"clickHandler",(async e=>{const element=e.target;if(element.closest(_selectors.default.EMBED.actions.mediaBrowser)){e.preventDefault();const fpType=this.getFilePickerTypeFromElement(element),params=await(0,_utils.displayFilepicker)(this.editor,fpType);this.trackFilePickerCallback(params,element,fpType)}e.target.closest(_selectors.default.EMBED.actions.addUrl)&&((0,_helpers.startMediaLoading)(this.root,_selectors.default.EMBED.type),this.urlChanged());element.closest(_selectors.default.EMBED.elements.track+" .addcomponent")&&(e.preventDefault(),this.addTrackComponent(element));element.closest(_selectors.default.EMBED.elements.track+" .removecomponent")&&(e.preventDefault(),this.removeTrackComponent(element));const trackDefaultAction=element.closest(_selectors.default.EMBED.elements.trackDefault);if(trackDefaultAction&&trackDefaultAction.checked){const getKind=el=>this.getTrackTypeFromTabPane(el.parentElement.closest(".tab-pane"));element.parentElement.closest(".tab-content").querySelectorAll(_selectors.default.EMBED.elements.trackDefault).forEach((select=>{select!==element&&getKind(element)===getKind(select)&&(select.checked=!1)}))}})),_defineProperty(this,"getMediaHTML",(form=>{this.mediaType=this.root.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer).dataset.mediaType;const tabContent=form.querySelector(".tab-content");return this["getMediaHTML"+this.mediaType[0].toUpperCase()+this.mediaType.substr(1)](tabContent)})),_defineProperty(this,"getMediaHTMLVideo",(tab=>{const details=document.querySelector(_selectors.default.EMBED.elements.mediaDetailsBody),context=this.getContextForMediaHTML(tab,details);context.width=details.querySelector(_selectors.default.EMBED.elements.width).value||!1,context.height=details.querySelector(_selectors.default.EMBED.elements.height).value||!1;const mediaPreviewContainer=details.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer);return context.poster=mediaPreviewContainer.dataset.mediaPoster||!1,context.sources?_templates.default.renderForPromise("tiny_media/embed/embed_media_video",context):""})),_defineProperty(this,"getMediaHTMLAudio",(tab=>{const details=document.querySelector(_selectors.default.EMBED.elements.mediaDetailsBody),context=this.getContextForMediaHTML(tab,details);return context.sources.length?_templates.default.renderForPromise("tiny_media/embed/embed_media_audio",context):""})),_defineProperty(this,"getContextForMediaHTML",((tab,details)=>{var _mediaPreviewContaine;const tracks=Array.from(tab.querySelectorAll(_selectors.default.EMBED.elements.track)).map((track=>{var _selectedLangTrack$da;const langTrack=track.querySelector(_selectors.default.EMBED.elements.trackLang),selectedLangTrack=langTrack.options[langTrack.selectedIndex];return{track:track.querySelector(_selectors.default.EMBED.elements.trackSource+" "+_selectors.default.EMBED.elements.url).value,kind:this.getTrackTypeFromTabPane(track.closest(".tab-pane")),label:track.querySelector(_selectors.default.EMBED.elements.trackLabel).value||langTrack.value,srclang:null!==(_selectedLangTrack$da=selectedLangTrack.dataset.languageCode)&&void 0!==_selectedLangTrack$da&&_selectedLangTrack$da,defaultTrack:track.querySelector(_selectors.default.EMBED.elements.trackDefault).checked?"true":null}})).filter((track=>!!track.track)),mediaPreviewContainer=details.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer);let sources=null!==(_mediaPreviewContaine=mediaPreviewContainer.dataset.originalUrl)&&void 0!==_mediaPreviewContaine?_mediaPreviewContaine:null;this.alternativeSources&&(this.alternativeSources[0]=sources,sources=this.alternativeSources);const title=details.querySelector(_selectors.default.EMBED.elements.title).value;mediaPreviewContainer.removeAttribute("data-original-url");const templateContext={sources:sources,tracks:tracks,showControls:details.querySelector(_selectors.default.EMBED.elements.mediaControl).checked,autoplay:details.querySelector(_selectors.default.EMBED.elements.mediaAutoplay).checked,muted:details.querySelector(_selectors.default.EMBED.elements.mediaMute).checked,loop:details.querySelector(_selectors.default.EMBED.elements.mediaLoop).checked,title:""!==title&&title.trim()};return"link"===this.mediaType&&(templateContext.description=Array.isArray(sources)?sources[0]:sources),templateContext})),_defineProperty(this,"handleDialogueSubmission",(async(event,modal)=>{const{html:html}=await this.getMediaHTML(modal.getRoot()[0]);html&&(this.isUpdating?(this.selectedMedia.outerHTML=html,this.isUpdating=!1):this.editor.insertContent(html))})),_defineProperty(this,"registerEventListeners",(async()=>{this.canShowFilePickerTrack&&this.root.addEventListener("click",this.clickHandler.bind(this)),this.root.addEventListener("input",(e=>{const urlEle=e.target.closest(_selectors.default.EMBED.elements.fromUrl);urlEle&&this.toggleUrlButton(urlEle,this.root)})),this.modalRoot.on(ModalEvents.hidden,(()=>{this.currentModal.destroy()})),this.modalRoot.on(ModalEvents.save,this.handleDialogueSubmission.bind(this))})),(0,_helpers.setPropertiesFromData)(this,_data)}urlChanged(){const url=this.root.querySelector(_selectors.default.EMBED.elements.fromUrl).value;url&&url!==this.currentUrl&&(this.mediaType=null,this.newMediaLink=!0,this.loadMediaPreview(url))}trackFilePickerCallback(params,element,fpType){if(""!==params.url){if(element.closest(".tab-pane")){if(element.closest(_selectors.default.EMBED.elements.source).querySelector(_selectors.default.EMBED.elements.url).value=params.url,"subtitle"===fpType){const subtitleLang=params.file.split(".vtt")[0].split("-").slice(-1)[0],langObj=(0,_embedhelpers.getMoodleLangObj)(subtitleLang,this.editor);if(langObj){const track=element.closest(_selectors.default.EMBED.elements.track);track.querySelector(_selectors.default.EMBED.elements.trackLabel).value=langObj.lang.trim(),track.querySelector(_selectors.default.EMBED.elements.trackLang).value=langObj.code}}}else this.newFileUpload=!0,this.resetCurrentMediaData(),this.loadMediaPreview(params.url)}}addTrackComponent(element){const trackElement=element.closest(_selectors.default.EMBED.elements.track),clone=trackElement.cloneNode(!0);trackElement.querySelector(".removecomponent-wrapper").classList.remove("hidden"),trackElement.querySelector(".addcomponent-wrapper").classList.add("hidden"),trackElement.parentNode.insertBefore(clone,trackElement.nextSibling)}removeTrackComponent(element){element.closest(_selectors.default.EMBED.elements.track).remove()}toggleUrlButton(input,root){const url=input.value;root.querySelector(_selectors.default.EMBED.actions.addUrl).disabled=!(""!==url&&(0,_helpers.isValidUrl)(url))}getMediaHTMLLink(){var _document$querySelect;const mediaPreviewContainer=document.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer),context={name:null!==(_document$querySelect=document.querySelector(_selectors.default.EMBED.elements.title).value)&&void 0!==_document$querySelect?_document$querySelect:mediaPreviewContainer.dataset.originalUrl,url:mediaPreviewContainer.dataset.originalUrl||!1};return context.url?_templates.default.renderForPromise("tiny_media/embed/embed_media_link",context):""}}})); //# sourceMappingURL=embedhandler.min.js.map \ No newline at end of file diff --git a/lib/editor/tiny/plugins/media/amd/build/embed/embedhandler.min.js.map b/lib/editor/tiny/plugins/media/amd/build/embed/embedhandler.min.js.map index b33c2abcc28..347951384b0 100644 --- a/lib/editor/tiny/plugins/media/amd/build/embed/embedhandler.min.js.map +++ b/lib/editor/tiny/plugins/media/amd/build/embed/embedhandler.min.js.map @@ -1 +1 @@ -{"version":3,"file":"embedhandler.min.js","sources":["../../src/embed/embedhandler.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 embed handler class.\n *\n * This handles anything that embed requires like:\n * - Calling the media preview in embedPreview.\n * - Loading the embed insert.\n * - Getting selected media data.\n * - Handles url and repository uploads.\n * - Reset embed insert when embed preview is deleted.\n * - Handles media embedding into tiny and etc.\n *\n * @module tiny_media/embed/embedhandler\n * @copyright 2024 Stevani Andolo \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from \"../selectors\";\nimport {EmbedInsert} from './embedinsert';\nimport {\n body,\n footer,\n setPropertiesFromData,\n isValidUrl,\n stopMediaLoading,\n startMediaLoading,\n} from '../helpers';\nimport * as ModalEvents from 'core/modal_events';\nimport {displayFilepicker} from 'editor_tiny/utils';\nimport {\n insertMediaTemplateContext,\n getHelpStrings,\n prepareMoodleLang,\n getMoodleLangObj,\n hasAudioVideoAttr,\n insertMediaThumbnailTemplateContext,\n} from \"./embedhelpers\";\nimport Templates from 'core/templates';\nimport {EmbedThumbnailInsert} from './embedthumbnailinsert';\n\nexport class EmbedHandler {\n\n constructor(data) {\n setPropertiesFromData(this, data); // Creates dynamic properties based on \"data\" param.\n }\n\n /**\n * Load the media insert dialogue.\n *\n * @param {object} templateContext Object template context\n */\n loadTemplatePromise = (templateContext) => {\n templateContext.elementid = this.editor.id;\n templateContext.bodyTemplate = Selectors.EMBED.template.body.insertMediaBody;\n templateContext.footerTemplate = Selectors.EMBED.template.footer.insertMediaFooter;\n templateContext.selector = Selectors.EMBED.type;\n\n Promise.all([body(templateContext, this.root), footer(templateContext, this.root)])\n .then(() => {\n (new EmbedInsert(this)).init();\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n };\n\n /**\n * Load the media thumbnail insert dialogue.\n *\n * @param {object} templateContext Object template context\n * @param {HTMLElement} root\n * @param {object} mediaData\n */\n loadInsertThumbnailTemplatePromise = async(templateContext, root, mediaData) => {\n Promise.all([body(templateContext, root.root), footer(templateContext, root.root)])\n .then(() => {\n if (!this.currentModal.insertMediaModal) {\n this.currentModal.insertMediaModal = this.currentModal;\n }\n\n if (root.uploadThumbnailModal) {\n this.currentModal.uploadThumbnailModal = root.uploadThumbnailModal;\n }\n\n this.thumbnailModalRoot = root.root;\n (new EmbedThumbnailInsert(this)).init(mediaData);\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n };\n\n /**\n * Loads the media preview dialogue.\n *\n * @param {object} embedPreview Object of embedPreview\n * @param {object} templateContext Object of template context\n */\n loadMediaDetails = async(embedPreview, templateContext) => {\n Promise.all([body(templateContext, this.root), footer(templateContext, this.root)])\n .then(() => {\n embedPreview.init();\n return;\n })\n .catch(error => {\n stopMediaLoading(this.root, Selectors.EMBED.type);\n window.console.log(error);\n });\n };\n\n /**\n * Reset the media/thumbnail insert modal form.\n *\n * @param {boolean} isMediaInsert Is current state media insert or thumbnail insert?\n */\n resetUploadForm = (isMediaInsert = true) => {\n if (isMediaInsert) {\n this.newMediaLink = false;\n this.fetchedMediaLinkTitle = null;\n this.resetCurrentMediaData();\n this.loadTemplatePromise(insertMediaTemplateContext(this));\n } else {\n this.loadInsertThumbnailTemplatePromise(\n insertMediaThumbnailTemplateContext(this), // Get template context for creating media thumbnail.\n {root: this.thumbnailModalRoot}, // Required root elements.\n this.mediaData // Get current media data.\n );\n }\n };\n\n /**\n * Get selected media data.\n *\n * @returns {null|object}\n */\n getMediaProperties = () => {\n const media = this.selectedMedia;\n if (!media) {\n return null;\n }\n\n const tracks = {\n subtitles: [],\n captions: [],\n descriptions: [],\n chapters: [],\n metadata: []\n };\n const sources = [];\n\n media.querySelectorAll('track').forEach((track) => {\n tracks[track.getAttribute('kind')].push({\n src: track.getAttribute('src'),\n srclang: track.getAttribute('srclang'),\n label: track.getAttribute('label'),\n defaultTrack: hasAudioVideoAttr(track, 'default')\n });\n });\n\n media.querySelectorAll('source').forEach((source) => {\n sources.push(source.src);\n });\n const title = media.getAttribute('title') ?? media.textContent;\n\n return {\n type: this.mediaType,\n sources,\n poster: media.getAttribute('poster'),\n title: title ? title.trim() : false,\n width: media.getAttribute('width'),\n height: media.getAttribute('height'),\n autoplay: hasAudioVideoAttr(media, 'autoplay'),\n loop: hasAudioVideoAttr(media, 'loop'),\n muted: hasAudioVideoAttr(media, 'muted'),\n controls: hasAudioVideoAttr(media, 'controls'),\n tracks,\n };\n };\n\n /**\n * Get selected media data.\n *\n * @returns {object}\n */\n getCurrentEmbedData = () => {\n const properties = this.getMediaProperties();\n if (!properties || this.newMediaLink) {\n return {media: {}};\n }\n\n const processedProperties = {};\n processedProperties.media = properties;\n processedProperties.link = false;\n\n return processedProperties;\n };\n\n /**\n * Get help strings for media subtitles and captions.\n *\n * @returns {null|object}\n */\n getHelpStrings = async() => {\n if (!this.helpStrings) {\n this.helpStrings = await getHelpStrings();\n }\n\n return this.helpStrings;\n };\n\n /**\n * Set template context for insert media dialogue.\n *\n * @param {object} data Object of media data\n * @returns {object}\n */\n getTemplateContext = async(data) => {\n const languages = prepareMoodleLang(this.editor);\n const helpIcons = Array.from(Object.entries(await this.getHelpStrings())).forEach(([key, text]) => {\n data[`${key.toLowerCase()}helpicon`] = {text};\n });\n\n return Object.assign({}, {\n elementid: this.editor.getElement().id,\n showFilePickerTrack: this.canShowFilePickerTrack,\n langsInstalled: languages.installed,\n langsAvailable: languages.available,\n media: true,\n isUpdating: this.isUpdating,\n }, data, helpIcons);\n };\n\n /**\n * Set and get media template context.\n *\n * @param {null|object} data Null or object of media data\n * @returns {Promise} A promise that resolves template context.\n */\n getMediaTemplateContext = async(data = null) => {\n if (!data) {\n data = Object.assign({}, this.getCurrentEmbedData());\n } else {\n if (data.hasOwnProperty('isUpdating')) {\n this.isUpdating = data.isUpdating;\n } else {\n this.isUpdating = Object.keys(data).length > 1;\n }\n }\n return await this.getTemplateContext(data);\n };\n\n /**\n * Handles changes in the media URL input field and loads a preview of the media if the URL has changed.\n */\n urlChanged() {\n const url = this.root.querySelector(Selectors.EMBED.elements.fromUrl).value;\n if (url && url !== this.currentUrl) {\n // Set to null on new url change.\n this.mediaType = null;\n\n // Flag as new media link insert.\n this.newMediaLink = true;\n this.loadMediaPreview(url);\n }\n }\n\n /**\n * Load the media preview dialogue.\n *\n * @param {string} url String of media url\n */\n loadMediaPreview = (url) => {\n (new EmbedInsert(this)).loadMediaPreview(url);\n };\n\n /**\n * Callback for file picker that previews the media or add the captions and subtitles.\n *\n * @param {object} params Object of media url and etc\n * @param {html} element Selected element.\n * @param {string} fpType Caption type.\n */\n trackFilePickerCallback(params, element, fpType) {\n if (params.url !== '') {\n const tabPane = element.closest('.tab-pane');\n if (tabPane) {\n element.closest(Selectors.EMBED.elements.source).querySelector(Selectors.EMBED.elements.url).value = params.url;\n\n if (fpType === 'subtitle') {\n // If the file is subtitle file. We need to match the language and label for that file.\n const subtitleLang = params.file.split('.vtt')[0].split('-').slice(-1)[0];\n const langObj = getMoodleLangObj(subtitleLang, this.editor);\n if (langObj) {\n const track = element.closest(Selectors.EMBED.elements.track);\n track.querySelector(Selectors.EMBED.elements.trackLabel).value = langObj.lang.trim();\n track.querySelector(Selectors.EMBED.elements.trackLang).value = langObj.code;\n }\n }\n } else {\n // Flag as new file upload.\n this.newFileUpload = true;\n this.resetCurrentMediaData();\n this.loadMediaPreview(params.url);\n }\n }\n }\n\n /**\n * Reset current media data.\n */\n resetCurrentMediaData = () => {\n // Reset the value of the following props.\n this.media = {};\n this.mediaType = null;\n this.selectedMedia = null;\n };\n\n /**\n * Add new html track element.\n *\n * @param {html} element\n */\n addTrackComponent(element) {\n const trackElement = element.closest(Selectors.EMBED.elements.track);\n const clone = trackElement.cloneNode(true);\n\n trackElement.querySelector('.removecomponent-wrapper').classList.remove('hidden');\n trackElement.querySelector('.addcomponent-wrapper').classList.add('hidden');\n trackElement.parentNode.insertBefore(clone, trackElement.nextSibling);\n }\n\n /**\n * Remove added html track element.\n *\n * @param {html} element\n */\n removeTrackComponent(element) {\n const sourceElement = element.closest(Selectors.EMBED.elements.track);\n sourceElement.remove();\n }\n\n /**\n * Get picker type based on the selected element.\n *\n * @param {html} element Selected element\n * @returns {string}\n */\n getFilePickerTypeFromElement = (element) => {\n if (element.closest(Selectors.EMBED.elements.posterSource)) {\n return 'image';\n }\n if (element.closest(Selectors.EMBED.elements.trackSource)) {\n return 'subtitle';\n }\n\n return 'media';\n };\n\n /**\n * Get captions/subtitles type.\n *\n * @param {html} tabPane\n * @returns {string}\n */\n getTrackTypeFromTabPane = (tabPane) => {\n return tabPane.getAttribute('data-track-kind');\n };\n\n /**\n * Handle click events.\n *\n * @param {html} e Selected element\n */\n clickHandler = async(e) => {\n const element = e.target;\n\n // Handle repository browsing.\n const mediaBrowser = element.closest(Selectors.EMBED.actions.mediaBrowser);\n if (mediaBrowser) {\n e.preventDefault();\n const fpType = this.getFilePickerTypeFromElement(element);\n const params = await displayFilepicker(this.editor, fpType);\n this.trackFilePickerCallback(params, element, fpType);\n }\n\n // Handles add media url.\n const addUrlEle = e.target.closest(Selectors.EMBED.actions.addUrl);\n if (addUrlEle) {\n startMediaLoading(this.root, Selectors.EMBED.type);\n this.urlChanged();\n }\n\n // Handles adding tracks.\n const addComponentTrackAction = element.closest(Selectors.EMBED.elements.track + ' .addcomponent');\n if (addComponentTrackAction) {\n e.preventDefault();\n this.addTrackComponent(element);\n }\n\n // Handles removing added tracks.\n const removeComponentTrackAction = element.closest(Selectors.EMBED.elements.track + ' .removecomponent');\n if (removeComponentTrackAction) {\n e.preventDefault();\n this.removeTrackComponent(element);\n }\n\n // Only allow one track per tab to be selected as \"default\".\n const trackDefaultAction = element.closest(Selectors.EMBED.elements.trackDefault);\n if (trackDefaultAction && trackDefaultAction.checked) {\n const getKind = (el) => this.getTrackTypeFromTabPane(el.parentElement.closest('.tab-pane'));\n\n element.parentElement\n .closest('.tab-content')\n .querySelectorAll(Selectors.EMBED.elements.trackDefault)\n .forEach((select) => {\n if (select !== element && getKind(element) === getKind(select)) {\n select.checked = false;\n }\n });\n }\n };\n\n /**\n * Enables or disables the URL-related buttons in the footer based on the current URL and input value.\n *\n * @param {html} input Url input field\n * @param {object} root\n */\n toggleUrlButton(input, root) {\n const url = input.value;\n const addUrl = root.querySelector(Selectors.EMBED.actions.addUrl);\n addUrl.disabled = !(url !== \"\" && isValidUrl(url));\n }\n\n /**\n * Get media html to be inserted or updated into tiny.\n *\n * @param {html} form Selected element\n * @returns {string} String of html\n */\n getMediaHTML = (form) => {\n this.mediaType = this.root.querySelector(Selectors.EMBED.elements.mediaPreviewContainer).dataset.mediaType;\n const tabContent = form.querySelector('.tab-content');\n const callback = 'getMediaHTML' + this.mediaType[0].toUpperCase() + this.mediaType.substr(1);\n return this[callback](tabContent);\n };\n\n /**\n * Get media as link.\n *\n * @returns {string} String of html.\n */\n getMediaHTMLLink() {\n const mediaPreviewContainer = document.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n const context = {\n name: document.querySelector(Selectors.EMBED.elements.title).value ?? mediaPreviewContainer.dataset.originalUrl,\n url: mediaPreviewContainer.dataset.originalUrl || false\n };\n\n return context.url ? Templates.renderForPromise('tiny_media/embed/embed_media_link', context) : '';\n }\n\n /**\n * Get media as video.\n *\n * @param {html} tab Selected element\n * @returns {string} String of html.\n */\n getMediaHTMLVideo = (tab) => {\n const details = document.querySelector(Selectors.EMBED.elements.mediaDetailsBody);\n const context = this.getContextForMediaHTML(tab, details);\n context.width = details.querySelector(Selectors.EMBED.elements.width).value || false;\n context.height = details.querySelector(Selectors.EMBED.elements.height).value || false;\n\n const mediaPreviewContainer = details.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n context.poster = mediaPreviewContainer.dataset.mediaPoster || false;\n return context.sources ? Templates.renderForPromise('tiny_media/embed/embed_media_video', context) : '';\n };\n\n /**\n * Get media as audio.\n *\n * @param {html} tab Selected element\n * @returns {string} String of html.\n */\n getMediaHTMLAudio = (tab) => {\n const details = document.querySelector(Selectors.EMBED.elements.mediaDetailsBody);\n const context = this.getContextForMediaHTML(tab, details);\n return context.sources.length ? Templates.renderForPromise('tiny_media/embed/embed_media_audio', context) : '';\n };\n\n /**\n * Get previewed media data.\n *\n * @param {html} tab Selected element\n * @param {html} details Selected element\n * @returns {object}\n */\n getContextForMediaHTML = (tab, details) => {\n const tracks = Array.from(tab.querySelectorAll(Selectors.EMBED.elements.track)).map(track => ({\n track: track.querySelector(Selectors.EMBED.elements.trackSource + ' ' + Selectors.EMBED.elements.url).value,\n kind: this.getTrackTypeFromTabPane(track.closest('.tab-pane')),\n label: track.querySelector(Selectors.EMBED.elements.trackLabel).value ||\n track.querySelector(Selectors.EMBED.elements.trackLang).value,\n srclang: track.querySelector(Selectors.EMBED.elements.trackLang).value,\n defaultTrack: track.querySelector(Selectors.EMBED.elements.trackDefault).checked ? \"true\" : null\n })).filter((track) => !!track.track);\n\n const mediaPreviewContainer = details.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n let sources = mediaPreviewContainer.dataset.originalUrl ?? null;\n\n // Let's check if media has more than one sources.\n if (this.alternativeSources) {\n // Always update the first item in this.alternativeSources to the new one.\n this.alternativeSources[0] = sources;\n // Override the sources to have all the updated sources.\n sources = this.alternativeSources;\n }\n\n const title = details.querySelector(Selectors.EMBED.elements.title).value;\n // Remove data-original-url attribute once it's extracted.\n mediaPreviewContainer.removeAttribute('data-original-url');\n\n const templateContext = {\n sources,\n tracks,\n showControls: details.querySelector(Selectors.EMBED.elements.mediaControl).checked,\n autoplay: details.querySelector(Selectors.EMBED.elements.mediaAutoplay).checked,\n muted: details.querySelector(Selectors.EMBED.elements.mediaMute).checked,\n loop: details.querySelector(Selectors.EMBED.elements.mediaLoop).checked,\n title: title !== '' ? title.trim() : false,\n };\n\n // Add description prop to templateContext if media type is \"link\".\n if (this.mediaType === 'link') {\n // Let's form an alternative title.\n templateContext.description = Array.isArray(sources) ? sources[0] : sources;\n }\n\n return templateContext;\n };\n\n /**\n * Handle the insert/update media in tiny editor.\n *\n * @param {event} event\n * @param {object} modal Object of current modal\n */\n handleDialogueSubmission = async(event, modal) => {\n const {html} = await this.getMediaHTML(modal.getRoot()[0]);\n if (html) {\n if (this.isUpdating) {\n this.selectedMedia.outerHTML = html;\n this.isUpdating = false;\n } else {\n this.editor.insertContent(html);\n }\n }\n };\n\n /**\n * Register insert media modal elements' events.\n */\n registerEventListeners = async() => {\n // Handles click events for insert media modal.\n if (this.canShowFilePickerTrack) {\n this.root.addEventListener('click', this.clickHandler.bind(this));\n }\n\n // Handles media adding using url input.\n this.root.addEventListener('input', (e) => {\n const urlEle = e.target.closest(Selectors.EMBED.elements.fromUrl);\n if (urlEle) {\n this.toggleUrlButton(urlEle, this.root);\n }\n });\n\n // Destroy created modal when it's closed.\n this.modalRoot.on(ModalEvents.hidden, () => {\n this.currentModal.destroy();\n });\n\n // Handles media insert to editor.\n this.modalRoot.on(ModalEvents.save, this.handleDialogueSubmission.bind(this));\n };\n}\n"],"names":["constructor","data","templateContext","elementid","this","editor","id","bodyTemplate","Selectors","EMBED","template","body","insertMediaBody","footerTemplate","footer","insertMediaFooter","selector","type","Promise","all","root","then","EmbedInsert","init","catch","error","window","console","log","async","mediaData","currentModal","insertMediaModal","uploadThumbnailModal","thumbnailModalRoot","EmbedThumbnailInsert","embedPreview","isMediaInsert","_this","newMediaLink","fetchedMediaLinkTitle","resetCurrentMediaData","loadTemplatePromise","loadInsertThumbnailTemplatePromise","media","selectedMedia","tracks","subtitles","captions","descriptions","chapters","metadata","sources","querySelectorAll","forEach","track","getAttribute","push","src","srclang","label","defaultTrack","source","title","textContent","mediaType","poster","trim","width","height","autoplay","loop","muted","controls","properties","getMediaProperties","processedProperties","link","helpStrings","languages","helpIcons","Array","from","Object","entries","getHelpStrings","_ref","key","text","toLowerCase","assign","getElement","showFilePickerTrack","canShowFilePickerTrack","langsInstalled","installed","langsAvailable","available","isUpdating","hasOwnProperty","keys","length","getCurrentEmbedData","getTemplateContext","url","loadMediaPreview","element","closest","elements","posterSource","trackSource","tabPane","e","target","actions","mediaBrowser","preventDefault","fpType","getFilePickerTypeFromElement","params","trackFilePickerCallback","addUrl","urlChanged","addTrackComponent","removeTrackComponent","trackDefaultAction","trackDefault","checked","getKind","el","getTrackTypeFromTabPane","parentElement","select","form","querySelector","mediaPreviewContainer","dataset","tabContent","toUpperCase","substr","tab","details","document","mediaDetailsBody","context","getContextForMediaHTML","value","mediaPoster","Templates","renderForPromise","map","kind","trackLabel","trackLang","filter","originalUrl","alternativeSources","removeAttribute","showControls","mediaControl","mediaAutoplay","mediaMute","mediaLoop","description","isArray","event","modal","html","getMediaHTML","getRoot","outerHTML","insertContent","addEventListener","clickHandler","bind","urlEle","fromUrl","toggleUrlButton","modalRoot","on","ModalEvents","hidden","destroy","save","handleDialogueSubmission","currentUrl","subtitleLang","file","split","slice","langObj","lang","code","newFileUpload","trackElement","clone","cloneNode","classList","remove","add","parentNode","insertBefore","nextSibling","input","disabled","getMediaHTMLLink","name"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"embedhandler.min.js","sources":["../../src/embed/embedhandler.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 embed handler class.\n *\n * This handles anything that embed requires like:\n * - Calling the media preview in embedPreview.\n * - Loading the embed insert.\n * - Getting selected media data.\n * - Handles url and repository uploads.\n * - Reset embed insert when embed preview is deleted.\n * - Handles media embedding into tiny and etc.\n *\n * @module tiny_media/embed/embedhandler\n * @copyright 2024 Stevani Andolo \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from \"../selectors\";\nimport {EmbedInsert} from './embedinsert';\nimport {\n body,\n footer,\n setPropertiesFromData,\n isValidUrl,\n stopMediaLoading,\n startMediaLoading,\n} from '../helpers';\nimport * as ModalEvents from 'core/modal_events';\nimport {displayFilepicker} from 'editor_tiny/utils';\nimport {\n insertMediaTemplateContext,\n getHelpStrings,\n prepareMoodleLang,\n getMoodleLangObj,\n hasAudioVideoAttr,\n insertMediaThumbnailTemplateContext,\n} from \"./embedhelpers\";\nimport Templates from 'core/templates';\nimport {EmbedThumbnailInsert} from './embedthumbnailinsert';\n\nexport class EmbedHandler {\n\n constructor(data) {\n setPropertiesFromData(this, data); // Creates dynamic properties based on \"data\" param.\n }\n\n /**\n * Load the media insert dialogue.\n *\n * @param {object} templateContext Object template context\n */\n loadTemplatePromise = (templateContext) => {\n templateContext.elementid = this.editor.id;\n templateContext.bodyTemplate = Selectors.EMBED.template.body.insertMediaBody;\n templateContext.footerTemplate = Selectors.EMBED.template.footer.insertMediaFooter;\n templateContext.selector = Selectors.EMBED.type;\n\n Promise.all([body(templateContext, this.root), footer(templateContext, this.root)])\n .then(() => {\n (new EmbedInsert(this)).init();\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n };\n\n /**\n * Load the media thumbnail insert dialogue.\n *\n * @param {object} templateContext Object template context\n * @param {HTMLElement} root\n * @param {object} mediaData\n */\n loadInsertThumbnailTemplatePromise = async(templateContext, root, mediaData) => {\n Promise.all([body(templateContext, root.root), footer(templateContext, root.root)])\n .then(() => {\n if (!this.currentModal.insertMediaModal) {\n this.currentModal.insertMediaModal = this.currentModal;\n }\n\n if (root.uploadThumbnailModal) {\n this.currentModal.uploadThumbnailModal = root.uploadThumbnailModal;\n }\n\n this.thumbnailModalRoot = root.root;\n (new EmbedThumbnailInsert(this)).init(mediaData);\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n };\n\n /**\n * Loads the media preview dialogue.\n *\n * @param {object} embedPreview Object of embedPreview\n * @param {object} templateContext Object of template context\n */\n loadMediaDetails = async(embedPreview, templateContext) => {\n Promise.all([body(templateContext, this.root), footer(templateContext, this.root)])\n .then(() => {\n embedPreview.init();\n return;\n })\n .catch(error => {\n stopMediaLoading(this.root, Selectors.EMBED.type);\n window.console.log(error);\n });\n };\n\n /**\n * Reset the media/thumbnail insert modal form.\n *\n * @param {boolean} isMediaInsert Is current state media insert or thumbnail insert?\n */\n resetUploadForm = (isMediaInsert = true) => {\n if (isMediaInsert) {\n this.newMediaLink = false;\n this.fetchedMediaLinkTitle = null;\n this.resetCurrentMediaData();\n this.loadTemplatePromise(insertMediaTemplateContext(this));\n } else {\n this.loadInsertThumbnailTemplatePromise(\n insertMediaThumbnailTemplateContext(this), // Get template context for creating media thumbnail.\n {root: this.thumbnailModalRoot}, // Required root elements.\n this.mediaData // Get current media data.\n );\n }\n };\n\n /**\n * Get selected media data.\n *\n * @returns {null|object}\n */\n getMediaProperties = () => {\n const media = this.selectedMedia;\n if (!media) {\n return null;\n }\n\n const tracks = {\n subtitles: [],\n captions: [],\n descriptions: [],\n chapters: [],\n metadata: []\n };\n const sources = [];\n\n media.querySelectorAll('track').forEach((track) => {\n tracks[track.getAttribute('kind')].push({\n src: track.getAttribute('src'),\n srclang: track.getAttribute('srclang'),\n label: track.getAttribute('label'),\n defaultTrack: hasAudioVideoAttr(track, 'default')\n });\n });\n\n media.querySelectorAll('source').forEach((source) => {\n sources.push(source.src);\n });\n const title = media.getAttribute('title') ?? media.textContent;\n\n return {\n type: this.mediaType,\n sources,\n poster: media.getAttribute('poster'),\n title: title ? title.trim() : false,\n width: media.getAttribute('width'),\n height: media.getAttribute('height'),\n autoplay: hasAudioVideoAttr(media, 'autoplay'),\n loop: hasAudioVideoAttr(media, 'loop'),\n muted: hasAudioVideoAttr(media, 'muted'),\n controls: hasAudioVideoAttr(media, 'controls'),\n tracks,\n };\n };\n\n /**\n * Get selected media data.\n *\n * @returns {object}\n */\n getCurrentEmbedData = () => {\n const properties = this.getMediaProperties();\n if (!properties || this.newMediaLink) {\n return {media: {}};\n }\n\n const processedProperties = {};\n processedProperties.media = properties;\n processedProperties.link = false;\n\n return processedProperties;\n };\n\n /**\n * Get help strings for media subtitles and captions.\n *\n * @returns {null|object}\n */\n getHelpStrings = async() => {\n if (!this.helpStrings) {\n this.helpStrings = await getHelpStrings();\n }\n\n return this.helpStrings;\n };\n\n /**\n * Set template context for insert media dialogue.\n *\n * @param {object} data Object of media data\n * @returns {object}\n */\n getTemplateContext = async(data) => {\n const languages = prepareMoodleLang(this.editor);\n const helpIcons = Array.from(Object.entries(await this.getHelpStrings())).forEach(([key, text]) => {\n data[`${key.toLowerCase()}helpicon`] = {text};\n });\n\n return Object.assign({}, {\n elementid: this.editor.getElement().id,\n showFilePickerTrack: this.canShowFilePickerTrack,\n langsInstalled: languages.installed,\n langsAvailable: languages.available,\n media: true,\n isUpdating: this.isUpdating,\n }, data, helpIcons);\n };\n\n /**\n * Set and get media template context.\n *\n * @param {null|object} data Null or object of media data\n * @returns {Promise} A promise that resolves template context.\n */\n getMediaTemplateContext = async(data = null) => {\n if (!data) {\n data = Object.assign({}, this.getCurrentEmbedData());\n } else {\n if (data.hasOwnProperty('isUpdating')) {\n this.isUpdating = data.isUpdating;\n } else {\n this.isUpdating = Object.keys(data).length > 1;\n }\n }\n return await this.getTemplateContext(data);\n };\n\n /**\n * Handles changes in the media URL input field and loads a preview of the media if the URL has changed.\n */\n urlChanged() {\n const url = this.root.querySelector(Selectors.EMBED.elements.fromUrl).value;\n if (url && url !== this.currentUrl) {\n // Set to null on new url change.\n this.mediaType = null;\n\n // Flag as new media link insert.\n this.newMediaLink = true;\n this.loadMediaPreview(url);\n }\n }\n\n /**\n * Load the media preview dialogue.\n *\n * @param {string} url String of media url\n */\n loadMediaPreview = (url) => {\n (new EmbedInsert(this)).loadMediaPreview(url);\n };\n\n /**\n * Callback for file picker that previews the media or add the captions and subtitles.\n *\n * @param {object} params Object of media url and etc\n * @param {html} element Selected element.\n * @param {string} fpType Caption type.\n */\n trackFilePickerCallback(params, element, fpType) {\n if (params.url !== '') {\n const tabPane = element.closest('.tab-pane');\n if (tabPane) {\n element.closest(Selectors.EMBED.elements.source).querySelector(Selectors.EMBED.elements.url).value = params.url;\n\n if (fpType === 'subtitle') {\n // If the file is subtitle file. We need to match the language and label for that file.\n const subtitleLang = params.file.split('.vtt')[0].split('-').slice(-1)[0];\n const langObj = getMoodleLangObj(subtitleLang, this.editor);\n if (langObj) {\n const track = element.closest(Selectors.EMBED.elements.track);\n track.querySelector(Selectors.EMBED.elements.trackLabel).value = langObj.lang.trim();\n track.querySelector(Selectors.EMBED.elements.trackLang).value = langObj.code;\n }\n }\n } else {\n // Flag as new file upload.\n this.newFileUpload = true;\n this.resetCurrentMediaData();\n this.loadMediaPreview(params.url);\n }\n }\n }\n\n /**\n * Reset current media data.\n */\n resetCurrentMediaData = () => {\n // Reset the value of the following props.\n this.media = {};\n this.mediaType = null;\n this.selectedMedia = null;\n };\n\n /**\n * Add new html track element.\n *\n * @param {html} element\n */\n addTrackComponent(element) {\n const trackElement = element.closest(Selectors.EMBED.elements.track);\n const clone = trackElement.cloneNode(true);\n\n trackElement.querySelector('.removecomponent-wrapper').classList.remove('hidden');\n trackElement.querySelector('.addcomponent-wrapper').classList.add('hidden');\n trackElement.parentNode.insertBefore(clone, trackElement.nextSibling);\n }\n\n /**\n * Remove added html track element.\n *\n * @param {html} element\n */\n removeTrackComponent(element) {\n const sourceElement = element.closest(Selectors.EMBED.elements.track);\n sourceElement.remove();\n }\n\n /**\n * Get picker type based on the selected element.\n *\n * @param {html} element Selected element\n * @returns {string}\n */\n getFilePickerTypeFromElement = (element) => {\n if (element.closest(Selectors.EMBED.elements.posterSource)) {\n return 'image';\n }\n if (element.closest(Selectors.EMBED.elements.trackSource)) {\n return 'subtitle';\n }\n\n return 'media';\n };\n\n /**\n * Get captions/subtitles type.\n *\n * @param {html} tabPane\n * @returns {string}\n */\n getTrackTypeFromTabPane = (tabPane) => {\n return tabPane.getAttribute('data-track-kind');\n };\n\n /**\n * Handle click events.\n *\n * @param {html} e Selected element\n */\n clickHandler = async(e) => {\n const element = e.target;\n\n // Handle repository browsing.\n const mediaBrowser = element.closest(Selectors.EMBED.actions.mediaBrowser);\n if (mediaBrowser) {\n e.preventDefault();\n const fpType = this.getFilePickerTypeFromElement(element);\n const params = await displayFilepicker(this.editor, fpType);\n this.trackFilePickerCallback(params, element, fpType);\n }\n\n // Handles add media url.\n const addUrlEle = e.target.closest(Selectors.EMBED.actions.addUrl);\n if (addUrlEle) {\n startMediaLoading(this.root, Selectors.EMBED.type);\n this.urlChanged();\n }\n\n // Handles adding tracks.\n const addComponentTrackAction = element.closest(Selectors.EMBED.elements.track + ' .addcomponent');\n if (addComponentTrackAction) {\n e.preventDefault();\n this.addTrackComponent(element);\n }\n\n // Handles removing added tracks.\n const removeComponentTrackAction = element.closest(Selectors.EMBED.elements.track + ' .removecomponent');\n if (removeComponentTrackAction) {\n e.preventDefault();\n this.removeTrackComponent(element);\n }\n\n // Only allow one track per tab to be selected as \"default\".\n const trackDefaultAction = element.closest(Selectors.EMBED.elements.trackDefault);\n if (trackDefaultAction && trackDefaultAction.checked) {\n const getKind = (el) => this.getTrackTypeFromTabPane(el.parentElement.closest('.tab-pane'));\n\n element.parentElement\n .closest('.tab-content')\n .querySelectorAll(Selectors.EMBED.elements.trackDefault)\n .forEach((select) => {\n if (select !== element && getKind(element) === getKind(select)) {\n select.checked = false;\n }\n });\n }\n };\n\n /**\n * Enables or disables the URL-related buttons in the footer based on the current URL and input value.\n *\n * @param {html} input Url input field\n * @param {object} root\n */\n toggleUrlButton(input, root) {\n const url = input.value;\n const addUrl = root.querySelector(Selectors.EMBED.actions.addUrl);\n addUrl.disabled = !(url !== \"\" && isValidUrl(url));\n }\n\n /**\n * Get media html to be inserted or updated into tiny.\n *\n * @param {html} form Selected element\n * @returns {string} String of html\n */\n getMediaHTML = (form) => {\n this.mediaType = this.root.querySelector(Selectors.EMBED.elements.mediaPreviewContainer).dataset.mediaType;\n const tabContent = form.querySelector('.tab-content');\n const callback = 'getMediaHTML' + this.mediaType[0].toUpperCase() + this.mediaType.substr(1);\n return this[callback](tabContent);\n };\n\n /**\n * Get media as link.\n *\n * @returns {string} String of html.\n */\n getMediaHTMLLink() {\n const mediaPreviewContainer = document.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n const context = {\n name: document.querySelector(Selectors.EMBED.elements.title).value ?? mediaPreviewContainer.dataset.originalUrl,\n url: mediaPreviewContainer.dataset.originalUrl || false\n };\n\n return context.url ? Templates.renderForPromise('tiny_media/embed/embed_media_link', context) : '';\n }\n\n /**\n * Get media as video.\n *\n * @param {html} tab Selected element\n * @returns {string} String of html.\n */\n getMediaHTMLVideo = (tab) => {\n const details = document.querySelector(Selectors.EMBED.elements.mediaDetailsBody);\n const context = this.getContextForMediaHTML(tab, details);\n context.width = details.querySelector(Selectors.EMBED.elements.width).value || false;\n context.height = details.querySelector(Selectors.EMBED.elements.height).value || false;\n\n const mediaPreviewContainer = details.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n context.poster = mediaPreviewContainer.dataset.mediaPoster || false;\n return context.sources ? Templates.renderForPromise('tiny_media/embed/embed_media_video', context) : '';\n };\n\n /**\n * Get media as audio.\n *\n * @param {html} tab Selected element\n * @returns {string} String of html.\n */\n getMediaHTMLAudio = (tab) => {\n const details = document.querySelector(Selectors.EMBED.elements.mediaDetailsBody);\n const context = this.getContextForMediaHTML(tab, details);\n return context.sources.length ? Templates.renderForPromise('tiny_media/embed/embed_media_audio', context) : '';\n };\n\n /**\n * Get previewed media data.\n *\n * @param {html} tab Selected element\n * @param {html} details Selected element\n * @returns {object}\n */\n getContextForMediaHTML = (tab, details) => {\n const tracks = Array.from(tab.querySelectorAll(Selectors.EMBED.elements.track)).map(track => {\n const langTrack = track.querySelector(Selectors.EMBED.elements.trackLang);\n const selectedLangTrack = langTrack.options[langTrack.selectedIndex];\n\n return {\n track: track.querySelector(Selectors.EMBED.elements.trackSource + ' ' + Selectors.EMBED.elements.url).value,\n kind: this.getTrackTypeFromTabPane(track.closest('.tab-pane')),\n label: track.querySelector(Selectors.EMBED.elements.trackLabel).value || langTrack.value,\n srclang: selectedLangTrack.dataset.languageCode ?? false,\n defaultTrack: track.querySelector(Selectors.EMBED.elements.trackDefault).checked ? \"true\" : null\n };\n }).filter((track) => !!track.track);\n\n const mediaPreviewContainer = details.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n let sources = mediaPreviewContainer.dataset.originalUrl ?? null;\n\n // Let's check if media has more than one sources.\n if (this.alternativeSources) {\n // Always update the first item in this.alternativeSources to the new one.\n this.alternativeSources[0] = sources;\n // Override the sources to have all the updated sources.\n sources = this.alternativeSources;\n }\n\n const title = details.querySelector(Selectors.EMBED.elements.title).value;\n // Remove data-original-url attribute once it's extracted.\n mediaPreviewContainer.removeAttribute('data-original-url');\n\n const templateContext = {\n sources,\n tracks,\n showControls: details.querySelector(Selectors.EMBED.elements.mediaControl).checked,\n autoplay: details.querySelector(Selectors.EMBED.elements.mediaAutoplay).checked,\n muted: details.querySelector(Selectors.EMBED.elements.mediaMute).checked,\n loop: details.querySelector(Selectors.EMBED.elements.mediaLoop).checked,\n title: title !== '' ? title.trim() : false,\n };\n\n // Add description prop to templateContext if media type is \"link\".\n if (this.mediaType === 'link') {\n // Let's form an alternative title.\n templateContext.description = Array.isArray(sources) ? sources[0] : sources;\n }\n\n return templateContext;\n };\n\n /**\n * Handle the insert/update media in tiny editor.\n *\n * @param {event} event\n * @param {object} modal Object of current modal\n */\n handleDialogueSubmission = async(event, modal) => {\n const {html} = await this.getMediaHTML(modal.getRoot()[0]);\n if (html) {\n if (this.isUpdating) {\n this.selectedMedia.outerHTML = html;\n this.isUpdating = false;\n } else {\n this.editor.insertContent(html);\n }\n }\n };\n\n /**\n * Register insert media modal elements' events.\n */\n registerEventListeners = async() => {\n // Handles click events for insert media modal.\n if (this.canShowFilePickerTrack) {\n this.root.addEventListener('click', this.clickHandler.bind(this));\n }\n\n // Handles media adding using url input.\n this.root.addEventListener('input', (e) => {\n const urlEle = e.target.closest(Selectors.EMBED.elements.fromUrl);\n if (urlEle) {\n this.toggleUrlButton(urlEle, this.root);\n }\n });\n\n // Destroy created modal when it's closed.\n this.modalRoot.on(ModalEvents.hidden, () => {\n this.currentModal.destroy();\n });\n\n // Handles media insert to editor.\n this.modalRoot.on(ModalEvents.save, this.handleDialogueSubmission.bind(this));\n };\n}\n"],"names":["constructor","data","templateContext","elementid","this","editor","id","bodyTemplate","Selectors","EMBED","template","body","insertMediaBody","footerTemplate","footer","insertMediaFooter","selector","type","Promise","all","root","then","EmbedInsert","init","catch","error","window","console","log","async","mediaData","currentModal","insertMediaModal","uploadThumbnailModal","thumbnailModalRoot","EmbedThumbnailInsert","embedPreview","isMediaInsert","_this","newMediaLink","fetchedMediaLinkTitle","resetCurrentMediaData","loadTemplatePromise","loadInsertThumbnailTemplatePromise","media","selectedMedia","tracks","subtitles","captions","descriptions","chapters","metadata","sources","querySelectorAll","forEach","track","getAttribute","push","src","srclang","label","defaultTrack","source","title","textContent","mediaType","poster","trim","width","height","autoplay","loop","muted","controls","properties","getMediaProperties","processedProperties","link","helpStrings","languages","helpIcons","Array","from","Object","entries","getHelpStrings","_ref","key","text","toLowerCase","assign","getElement","showFilePickerTrack","canShowFilePickerTrack","langsInstalled","installed","langsAvailable","available","isUpdating","hasOwnProperty","keys","length","getCurrentEmbedData","getTemplateContext","url","loadMediaPreview","element","closest","elements","posterSource","trackSource","tabPane","e","target","actions","mediaBrowser","preventDefault","fpType","getFilePickerTypeFromElement","params","trackFilePickerCallback","addUrl","urlChanged","addTrackComponent","removeTrackComponent","trackDefaultAction","trackDefault","checked","getKind","el","getTrackTypeFromTabPane","parentElement","select","form","querySelector","mediaPreviewContainer","dataset","tabContent","toUpperCase","substr","tab","details","document","mediaDetailsBody","context","getContextForMediaHTML","value","mediaPoster","Templates","renderForPromise","map","langTrack","trackLang","selectedLangTrack","options","selectedIndex","kind","trackLabel","languageCode","filter","originalUrl","alternativeSources","removeAttribute","showControls","mediaControl","mediaAutoplay","mediaMute","mediaLoop","description","isArray","event","modal","html","getMediaHTML","getRoot","outerHTML","insertContent","addEventListener","clickHandler","bind","urlEle","fromUrl","toggleUrlButton","modalRoot","on","ModalEvents","hidden","destroy","save","handleDialogueSubmission","currentUrl","subtitleLang","file","split","slice","langObj","lang","code","newFileUpload","trackElement","clone","cloneNode","classList","remove","add","parentNode","insertBefore","nextSibling","input","disabled","getMediaHTMLLink","name"],"mappings":"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"} \ No newline at end of file diff --git a/lib/editor/tiny/plugins/media/amd/build/embed/embedhelpers.min.js b/lib/editor/tiny/plugins/media/amd/build/embed/embedhelpers.min.js index 3ea334ee3fe..e4ab831a4ac 100644 --- a/lib/editor/tiny/plugins/media/amd/build/embed/embedhelpers.min.js +++ b/lib/editor/tiny/plugins/media/amd/build/embed/embedhelpers.min.js @@ -7,6 +7,6 @@ define("tiny_media/embed/embedhelpers",["exports","../selectors","core/str","../ * @module tiny_media/embed/embedhelpers * @copyright 2024 Stevani Andolo * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.prepareMoodleLang=_exports.mediaDetailsTemplateContext=_exports.insertMediaThumbnailTemplateContext=_exports.insertMediaTemplateContext=_exports.hasAudioVideoAttr=_exports.getSelectedMediaElement=_exports.getMoodleLangObj=_exports.getMediaTitle=_exports.getHelpStrings=_exports.getEmbeddedMediaDetails=_exports.fetchPreview=_exports.checkMediaType=void 0,_selectors=_interopRequireDefault(_selectors),_ajax=_interopRequireDefault(_ajax);_exports.insertMediaTemplateContext=props=>({mediaType:props.mediaType,showDropzone:props.canShowDropZone,showFilePicker:props.canShowFilePicker,fileType:"audio/video"});_exports.insertMediaThumbnailTemplateContext=props=>({elementid:props.editor.id,showDropzone:props.canShowDropZone,showImageFilePicker:props.canShowImageFilePicker,bodyTemplate:_selectors.default.EMBED.template.body.insertMediaBody,footerTemplate:_selectors.default.EMBED.template.footer.insertMediaFooter,fileType:"image",selector:_selectors.default.EMBED.type});_exports.getSelectedMediaElement=editor=>{let mediaType=null,selectedMedia=null;const mediaElm=editor.selection.getNode();return mediaElm?"video"===mediaElm.nodeName.toLowerCase()||"audio"===mediaElm.nodeName.toLowerCase()?(mediaType=mediaElm.nodeName.toLowerCase(),selectedMedia=mediaElm):mediaElm.querySelector("video")?(mediaType="video",selectedMedia=mediaElm.querySelector("video")):mediaElm.querySelector("audio")?(mediaType="audio",selectedMedia=mediaElm.querySelector("audio")):"a"===mediaElm.nodeName.toLowerCase()&&(selectedMedia=mediaElm):(mediaType=null,selectedMedia=null),[mediaType,selectedMedia]};_exports.fetchPreview=async(url,contextId)=>{const request={methodname:"tiny_media_preview",args:{contextid:contextId,content:url}};return(await _ajax.default.call([request])[0]).content};_exports.checkMediaType=async url=>{try{const contentType=(await fetch(url,{method:"HEAD"})).headers.get("Content-type");return contentType?contentType.startsWith("video/")?"video":contentType.startsWith("audio/")?"audio":null:null}catch(e){return null}};_exports.getMediaTitle=async(url,props)=>{const extension=url.split(".").pop().split("?")[0];return props.acceptedMediaTypes.includes(".".concat(extension))?(0,_helpers.getFileName)(url):null};_exports.mediaDetailsTemplateContext=async props=>({...{bodyTemplate:_selectors.default.EMBED.template.body.mediaDetailsBody,footerTemplate:_selectors.default.EMBED.template.footer.mediaDetailsFooter,isLink:"link"===props.mediaType,isVideo:"video"===props.mediaType,showControl:"video"===props.mediaType||"audio"===props.mediaType,isUpdating:props.isUpdating,isNewFileOrLinkUpload:props.newMediaLink||props.newFileUpload,selector:_selectors.default.EMBED.type},...props});_exports.getHelpStrings=async()=>{const[subtitles,captions,descriptions,chapters,metadata,customsize,linkcustomsize]=await(0,_str.getStrings)(["subtitles_help","captions_help","descriptions_help","chapters_help","metadata_help","customsize_help","linkcustomsize_help"].map((key=>({key:key,component:_common.component}))));return{subtitles:subtitles,captions:captions,descriptions:descriptions,chapters:chapters,metadata:metadata,customsize:customsize,linkcustomsize:linkcustomsize}};_exports.prepareMoodleLang=editor=>{const moodleLangs=(0,_options.getMoodleLang)(editor),currentLanguage=(0,_options.getCurrentLanguage)(editor);return{installed:Object.entries(moodleLangs.installed).map((_ref=>{let[lang,code]=_ref;return{lang:lang,code:code,default:lang===currentLanguage}})),available:Object.entries(moodleLangs.available).map((_ref2=>{let[lang,code]=_ref2;return{lang:lang,code:code,default:lang===currentLanguage}}))}};_exports.getMoodleLangObj=(subtitleLang,editor)=>{const{available:available}=(0,_options.getMoodleLang)(editor);return available[subtitleLang]?{lang:subtitleLang,code:available[subtitleLang]}:null};_exports.getEmbeddedMediaDetails=props=>{var _props$media$poster;const tracks={subtitles:[],captions:[],descriptions:[],chapters:[],metadata:[]};props.root.querySelectorAll(_selectors.default.EMBED.elements.mediaMetadataTabPane).forEach((metaData=>{metaData.querySelectorAll(_selectors.default.EMBED.elements.track).forEach((track=>{tracks[metaData.dataset.trackKind].push({src:track.querySelector(_selectors.default.EMBED.elements.url).value,srclang:track.querySelector(_selectors.default.EMBED.elements.trackLang).value,label:track.querySelector(_selectors.default.EMBED.elements.trackLabel).value,defaultTrack:track.querySelector(_selectors.default.EMBED.elements.trackDefault).checked})}))}));const querySelector=element=>props.root.querySelector(element),mediaDataProps={};return mediaDataProps.media={type:props.mediaType,sources:props.media,poster:null!==(_props$media$poster=props.media.poster)&&void 0!==_props$media$poster?_props$media$poster:null,title:querySelector(_selectors.default.EMBED.elements.title).value,width:querySelector(_selectors.default.EMBED.elements.width).value,height:querySelector(_selectors.default.EMBED.elements.height).value,autoplay:querySelector(_selectors.default.EMBED.elements.mediaAutoplay).checked,loop:querySelector(_selectors.default.EMBED.elements.mediaLoop).checked,muted:querySelector(_selectors.default.EMBED.elements.mediaMute).checked,controls:querySelector(_selectors.default.EMBED.elements.mediaControl).checked,tracks:tracks},mediaDataProps.link=!1,mediaDataProps};_exports.hasAudioVideoAttr=(elem,attr)=>elem.hasAttribute(attr)&&(elem.getAttribute(attr)||""===elem.getAttribute(attr))})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.prepareMoodleLang=_exports.mediaDetailsTemplateContext=_exports.insertMediaThumbnailTemplateContext=_exports.insertMediaTemplateContext=_exports.hasAudioVideoAttr=_exports.getSelectedMediaElement=_exports.getMoodleLangObj=_exports.getMediaTitle=_exports.getHelpStrings=_exports.getEmbeddedMediaDetails=_exports.fetchPreview=_exports.checkMediaType=void 0,_selectors=_interopRequireDefault(_selectors),_ajax=_interopRequireDefault(_ajax);_exports.insertMediaTemplateContext=props=>({mediaType:props.mediaType,showDropzone:props.canShowDropZone,showFilePicker:props.canShowFilePicker,fileType:"audio/video"});_exports.insertMediaThumbnailTemplateContext=props=>({elementid:props.editor.id,showDropzone:props.canShowDropZone,showImageFilePicker:props.canShowImageFilePicker,bodyTemplate:_selectors.default.EMBED.template.body.insertMediaBody,footerTemplate:_selectors.default.EMBED.template.footer.insertMediaFooter,fileType:"image",selector:_selectors.default.EMBED.type});_exports.getSelectedMediaElement=editor=>{let mediaType=null,selectedMedia=null;const mediaElm=editor.selection.getNode();return mediaElm?"video"===mediaElm.nodeName.toLowerCase()||"audio"===mediaElm.nodeName.toLowerCase()?(mediaType=mediaElm.nodeName.toLowerCase(),selectedMedia=mediaElm):mediaElm.querySelector("video")?(mediaType="video",selectedMedia=mediaElm.querySelector("video")):mediaElm.querySelector("audio")?(mediaType="audio",selectedMedia=mediaElm.querySelector("audio")):"a"===mediaElm.nodeName.toLowerCase()&&(selectedMedia=mediaElm):(mediaType=null,selectedMedia=null),[mediaType,selectedMedia]};_exports.fetchPreview=async(url,contextId)=>{const request={methodname:"tiny_media_preview",args:{contextid:contextId,content:url}};return(await _ajax.default.call([request])[0]).content};_exports.checkMediaType=async url=>{try{const contentType=(await fetch(url,{method:"HEAD"})).headers.get("Content-type");return contentType?contentType.startsWith("video/")?"video":contentType.startsWith("audio/")?"audio":null:null}catch(e){return null}};_exports.getMediaTitle=async(url,props)=>{const extension=url.split(".").pop().split("?")[0];return props.acceptedMediaTypes.includes(".".concat(extension))?(0,_helpers.getFileName)(url):null};_exports.mediaDetailsTemplateContext=async props=>({...{bodyTemplate:_selectors.default.EMBED.template.body.mediaDetailsBody,footerTemplate:_selectors.default.EMBED.template.footer.mediaDetailsFooter,isLink:"link"===props.mediaType,isVideo:"video"===props.mediaType,showControl:"video"===props.mediaType||"audio"===props.mediaType,isUpdating:props.isUpdating,isNewFileOrLinkUpload:props.newMediaLink||props.newFileUpload,selector:_selectors.default.EMBED.type},...props});_exports.getHelpStrings=async()=>{const[subtitles,captions,descriptions,chapters,metadata,customsize,linkcustomsize]=await(0,_str.getStrings)(["subtitles_help","captions_help","descriptions_help","chapters_help","metadata_help","customsize_help","linkcustomsize_help"].map((key=>({key:key,component:_common.component}))));return{subtitles:subtitles,captions:captions,descriptions:descriptions,chapters:chapters,metadata:metadata,customsize:customsize,linkcustomsize:linkcustomsize}};_exports.prepareMoodleLang=editor=>{const moodleLangs=(0,_options.getMoodleLang)(editor),currentLanguage=(0,_options.getCurrentLanguage)(editor);return{installed:Object.entries(moodleLangs.installed).map((_ref=>{let[code,lang]=_ref;return{lang:lang,code:code,default:code===currentLanguage}})),available:Object.entries(moodleLangs.available).map((_ref2=>{let[code,lang]=_ref2;return{lang:lang,code:code,default:code===currentLanguage}}))}};_exports.getMoodleLangObj=(subtitleLang,editor)=>{const{available:available}=(0,_options.getMoodleLang)(editor);return available[subtitleLang]?{lang:subtitleLang,code:available[subtitleLang]}:null};_exports.getEmbeddedMediaDetails=props=>{var _props$media$poster;const tracks={subtitles:[],captions:[],descriptions:[],chapters:[],metadata:[]};props.root.querySelectorAll(_selectors.default.EMBED.elements.mediaMetadataTabPane).forEach((metaData=>{metaData.querySelectorAll(_selectors.default.EMBED.elements.track).forEach((track=>{tracks[metaData.dataset.trackKind].push({src:track.querySelector(_selectors.default.EMBED.elements.url).value,srclang:track.querySelector(_selectors.default.EMBED.elements.trackLang).value,label:track.querySelector(_selectors.default.EMBED.elements.trackLabel).value,defaultTrack:track.querySelector(_selectors.default.EMBED.elements.trackDefault).checked})}))}));const querySelector=element=>props.root.querySelector(element),mediaDataProps={};return mediaDataProps.media={type:props.mediaType,sources:props.media,poster:null!==(_props$media$poster=props.media.poster)&&void 0!==_props$media$poster?_props$media$poster:null,title:querySelector(_selectors.default.EMBED.elements.title).value,width:querySelector(_selectors.default.EMBED.elements.width).value,height:querySelector(_selectors.default.EMBED.elements.height).value,autoplay:querySelector(_selectors.default.EMBED.elements.mediaAutoplay).checked,loop:querySelector(_selectors.default.EMBED.elements.mediaLoop).checked,muted:querySelector(_selectors.default.EMBED.elements.mediaMute).checked,controls:querySelector(_selectors.default.EMBED.elements.mediaControl).checked,tracks:tracks},mediaDataProps.link=!1,mediaDataProps};_exports.hasAudioVideoAttr=(elem,attr)=>elem.hasAttribute(attr)&&(elem.getAttribute(attr)||""===elem.getAttribute(attr))})); //# sourceMappingURL=embedhelpers.min.js.map \ No newline at end of file diff --git a/lib/editor/tiny/plugins/media/amd/build/embed/embedhelpers.min.js.map b/lib/editor/tiny/plugins/media/amd/build/embed/embedhelpers.min.js.map index c41241f0b26..911d63b36ad 100644 --- a/lib/editor/tiny/plugins/media/amd/build/embed/embedhelpers.min.js.map +++ b/lib/editor/tiny/plugins/media/amd/build/embed/embedhelpers.min.js.map @@ -1 +1 @@ -{"version":3,"file":"embedhelpers.min.js","sources":["../../src/embed/embedhelpers.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 embed helpers.\n *\n * This provides easy access to any classes without instantiating a new object.\n *\n * @module tiny_media/embed/embedhelpers\n * @copyright 2024 Stevani Andolo \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from '../selectors';\nimport {getStrings} from 'core/str';\nimport {component} from \"../common\";\nimport {getCurrentLanguage, getMoodleLang} from 'editor_tiny/options';\nimport Ajax from 'core/ajax';\nimport {getFileName} from '../helpers';\n\n/**\n * Return template context for insert media.\n *\n * @param {object} props\n * @returns {object}\n */\nexport const insertMediaTemplateContext = (props) => {\n return {\n mediaType: props.mediaType,\n showDropzone: props.canShowDropZone,\n showFilePicker: props.canShowFilePicker,\n fileType: 'audio/video',\n };\n};\n\n/**\n * Return template context for insert media.\n *\n * @param {object} props\n * @returns {object}\n */\nexport const insertMediaThumbnailTemplateContext = (props) => {\n return {\n elementid: props.editor.id,\n showDropzone: props.canShowDropZone,\n showImageFilePicker: props.canShowImageFilePicker,\n bodyTemplate: Selectors.EMBED.template.body.insertMediaBody,\n footerTemplate: Selectors.EMBED.template.footer.insertMediaFooter,\n fileType: 'image',\n selector: Selectors.EMBED.type,\n };\n};\n\n/**\n * Return selected media type and element.\n *\n * @param {editor} editor\n * @returns {Array}\n */\nexport const getSelectedMediaElement = (editor) => {\n let mediaType = null;\n let selectedMedia = null;\n const mediaElm = editor.selection.getNode();\n\n if (!mediaElm) {\n mediaType = null;\n selectedMedia = null;\n } else if (mediaElm.nodeName.toLowerCase() === 'video' || mediaElm.nodeName.toLowerCase() === 'audio') {\n mediaType = mediaElm.nodeName.toLowerCase();\n selectedMedia = mediaElm;\n } else if (mediaElm.querySelector('video')) {\n mediaType = 'video';\n selectedMedia = mediaElm.querySelector('video');\n } else if (mediaElm.querySelector('audio')) {\n mediaType = 'audio';\n selectedMedia = mediaElm.querySelector('audio');\n } else if (mediaElm.nodeName.toLowerCase() === 'a') {\n selectedMedia = mediaElm;\n }\n\n return [mediaType, selectedMedia];\n};\n\n/**\n * Returns result of media filtering.\n *\n * @param {string} url\n * @param {string} contextId\n * @returns {string}\n */\nexport const fetchPreview = async(url, contextId) => {\n const request = {\n methodname: 'tiny_media_preview',\n args: {\n contextid: contextId, // Use the system one.\n content: url,\n }\n };\n const responseObj = await Ajax.call([request])[0];\n return responseObj.content;\n};\n\n/**\n * Returns media type.\n *\n * @param {string} url\n * @returns {string|null}\n */\nexport const checkMediaType = async(url) => {\n try {\n const response = await fetch(url, {method: 'HEAD'});\n const contentType = response.headers.get('Content-type');\n\n if (!contentType) {\n return null;\n }\n\n if (contentType.startsWith('video/')) {\n return 'video';\n } else if (contentType.startsWith('audio/')) {\n return 'audio';\n }\n\n return null;\n } catch (e) {\n return null;\n }\n};\n\n/**\n * Returns media title.\n *\n * @param {string} url\n * @param {object} props\n * @returns {string|null} String of media title.\n */\nexport const getMediaTitle = async(url, props) => {\n const extension = url.split('.').pop().split('?')[0];\n if (props.acceptedMediaTypes.includes(`.${extension}`)) {\n return getFileName(url);\n }\n\n return null;\n};\n\n/**\n * Return template context for media details.\n *\n * @param {object} props\n * @returns {object}\n */\nexport const mediaDetailsTemplateContext = async(props) => {\n const context = {\n bodyTemplate: Selectors.EMBED.template.body.mediaDetailsBody,\n footerTemplate: Selectors.EMBED.template.footer.mediaDetailsFooter,\n isLink: (props.mediaType === 'link'),\n isVideo: (props.mediaType === 'video'),\n showControl: (props.mediaType === 'video' || props.mediaType === 'audio'),\n isUpdating: props.isUpdating,\n isNewFileOrLinkUpload: (props.newMediaLink || props.newFileUpload),\n selector: Selectors.EMBED.type,\n };\n\n return {...context, ...props};\n};\n\n/**\n * Get help strings.\n *\n * @returns {object}\n */\nexport const getHelpStrings = async() => {\n const [\n subtitles,\n captions,\n descriptions,\n chapters,\n metadata,\n customsize,\n linkcustomsize,\n ] = await getStrings([\n 'subtitles_help',\n 'captions_help',\n 'descriptions_help',\n 'chapters_help',\n 'metadata_help',\n 'customsize_help',\n 'linkcustomsize_help',\n ].map((key) => ({\n key,\n component,\n })));\n\n return {\n subtitles,\n captions,\n descriptions,\n chapters,\n metadata,\n customsize,\n linkcustomsize,\n };\n};\n\n/**\n * Get current moodle languages.\n *\n * @param {editor} editor\n * @returns {object}\n */\nexport const prepareMoodleLang = (editor) => {\n const moodleLangs = getMoodleLang(editor);\n const currentLanguage = getCurrentLanguage(editor);\n\n const installed = Object.entries(moodleLangs.installed).map(([lang, code]) => ({\n lang,\n code,\n \"default\": lang === currentLanguage,\n }));\n\n const available = Object.entries(moodleLangs.available).map(([lang, code]) => ({\n lang,\n code,\n \"default\": lang === currentLanguage,\n }));\n\n return {\n installed,\n available,\n };\n};\n\n/**\n * Return moodle lang.\n *\n * @param {string} subtitleLang\n * @param {editor} editor\n * @returns {object|null}\n */\nexport const getMoodleLangObj = (subtitleLang, editor) => {\n const {available} = getMoodleLang(editor);\n\n if (available[subtitleLang]) {\n return {\n lang: subtitleLang,\n code: available[subtitleLang],\n };\n }\n\n return null;\n};\n\n/**\n * Get media data from the inserted media.\n *\n * @param {object} props\n * @returns {object}\n */\nexport const getEmbeddedMediaDetails = (props) => {\n const tracks = {\n subtitles: [],\n captions: [],\n descriptions: [],\n chapters: [],\n metadata: []\n };\n\n const mediaMetadata = props.root.querySelectorAll(Selectors.EMBED.elements.mediaMetadataTabPane);\n mediaMetadata.forEach(metaData => {\n const trackElements = metaData.querySelectorAll(Selectors.EMBED.elements.track);\n trackElements.forEach(track => {\n tracks[metaData.dataset.trackKind].push({\n src: track.querySelector(Selectors.EMBED.elements.url).value,\n srclang: track.querySelector(Selectors.EMBED.elements.trackLang).value,\n label: track.querySelector(Selectors.EMBED.elements.trackLabel).value,\n defaultTrack: track.querySelector(Selectors.EMBED.elements.trackDefault).checked,\n });\n });\n });\n\n const querySelector = (element) => props.root.querySelector(element);\n const mediaDataProps = {};\n mediaDataProps.media = {\n type: props.mediaType,\n sources: props.media,\n poster: props.media.poster ?? null,\n title: querySelector(Selectors.EMBED.elements.title).value,\n width: querySelector(Selectors.EMBED.elements.width).value,\n height: querySelector(Selectors.EMBED.elements.height).value,\n autoplay: querySelector(Selectors.EMBED.elements.mediaAutoplay).checked,\n loop: querySelector(Selectors.EMBED.elements.mediaLoop).checked,\n muted: querySelector(Selectors.EMBED.elements.mediaMute).checked,\n controls: querySelector(Selectors.EMBED.elements.mediaControl).checked,\n tracks,\n };\n mediaDataProps.link = false;\n return mediaDataProps;\n};\n\n/**\n * Check for video/audio attributes.\n *\n * @param {HTMLElement} elem\n * @param {string} attr Attribute name\n * @returns {boolean}\n */\nexport const hasAudioVideoAttr = (elem, attr) => {\n // As explained in MDL-64175, some OS (like Ubuntu), are removing the value for these attributes.\n // So in order to check if attr=\"true\", we need to check if the attribute exists and if the value is empty or true.\n return (elem.hasAttribute(attr) && (elem.getAttribute(attr) || elem.getAttribute(attr) === ''));\n};\n"],"names":["props","mediaType","showDropzone","canShowDropZone","showFilePicker","canShowFilePicker","fileType","elementid","editor","id","showImageFilePicker","canShowImageFilePicker","bodyTemplate","Selectors","EMBED","template","body","insertMediaBody","footerTemplate","footer","insertMediaFooter","selector","type","selectedMedia","mediaElm","selection","getNode","nodeName","toLowerCase","querySelector","async","url","contextId","request","methodname","args","contextid","content","Ajax","call","contentType","fetch","method","headers","get","startsWith","e","extension","split","pop","acceptedMediaTypes","includes","mediaDetailsBody","mediaDetailsFooter","isLink","isVideo","showControl","isUpdating","isNewFileOrLinkUpload","newMediaLink","newFileUpload","subtitles","captions","descriptions","chapters","metadata","customsize","linkcustomsize","map","key","component","moodleLangs","currentLanguage","installed","Object","entries","_ref","lang","code","available","_ref2","subtitleLang","tracks","root","querySelectorAll","elements","mediaMetadataTabPane","forEach","metaData","track","dataset","trackKind","push","src","value","srclang","trackLang","label","trackLabel","defaultTrack","trackDefault","checked","element","mediaDataProps","media","sources","poster","title","width","height","autoplay","mediaAutoplay","loop","mediaLoop","muted","mediaMute","controls","mediaControl","link","elem","attr","hasAttribute","getAttribute"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"embedhelpers.min.js","sources":["../../src/embed/embedhelpers.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 embed helpers.\n *\n * This provides easy access to any classes without instantiating a new object.\n *\n * @module tiny_media/embed/embedhelpers\n * @copyright 2024 Stevani Andolo \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from '../selectors';\nimport {getStrings} from 'core/str';\nimport {component} from \"../common\";\nimport {getCurrentLanguage, getMoodleLang} from 'editor_tiny/options';\nimport Ajax from 'core/ajax';\nimport {getFileName} from '../helpers';\n\n/**\n * Return template context for insert media.\n *\n * @param {object} props\n * @returns {object}\n */\nexport const insertMediaTemplateContext = (props) => {\n return {\n mediaType: props.mediaType,\n showDropzone: props.canShowDropZone,\n showFilePicker: props.canShowFilePicker,\n fileType: 'audio/video',\n };\n};\n\n/**\n * Return template context for insert media.\n *\n * @param {object} props\n * @returns {object}\n */\nexport const insertMediaThumbnailTemplateContext = (props) => {\n return {\n elementid: props.editor.id,\n showDropzone: props.canShowDropZone,\n showImageFilePicker: props.canShowImageFilePicker,\n bodyTemplate: Selectors.EMBED.template.body.insertMediaBody,\n footerTemplate: Selectors.EMBED.template.footer.insertMediaFooter,\n fileType: 'image',\n selector: Selectors.EMBED.type,\n };\n};\n\n/**\n * Return selected media type and element.\n *\n * @param {editor} editor\n * @returns {Array}\n */\nexport const getSelectedMediaElement = (editor) => {\n let mediaType = null;\n let selectedMedia = null;\n const mediaElm = editor.selection.getNode();\n\n if (!mediaElm) {\n mediaType = null;\n selectedMedia = null;\n } else if (mediaElm.nodeName.toLowerCase() === 'video' || mediaElm.nodeName.toLowerCase() === 'audio') {\n mediaType = mediaElm.nodeName.toLowerCase();\n selectedMedia = mediaElm;\n } else if (mediaElm.querySelector('video')) {\n mediaType = 'video';\n selectedMedia = mediaElm.querySelector('video');\n } else if (mediaElm.querySelector('audio')) {\n mediaType = 'audio';\n selectedMedia = mediaElm.querySelector('audio');\n } else if (mediaElm.nodeName.toLowerCase() === 'a') {\n selectedMedia = mediaElm;\n }\n\n return [mediaType, selectedMedia];\n};\n\n/**\n * Returns result of media filtering.\n *\n * @param {string} url\n * @param {string} contextId\n * @returns {string}\n */\nexport const fetchPreview = async(url, contextId) => {\n const request = {\n methodname: 'tiny_media_preview',\n args: {\n contextid: contextId, // Use the system one.\n content: url,\n }\n };\n const responseObj = await Ajax.call([request])[0];\n return responseObj.content;\n};\n\n/**\n * Returns media type.\n *\n * @param {string} url\n * @returns {string|null}\n */\nexport const checkMediaType = async(url) => {\n try {\n const response = await fetch(url, {method: 'HEAD'});\n const contentType = response.headers.get('Content-type');\n\n if (!contentType) {\n return null;\n }\n\n if (contentType.startsWith('video/')) {\n return 'video';\n } else if (contentType.startsWith('audio/')) {\n return 'audio';\n }\n\n return null;\n } catch (e) {\n return null;\n }\n};\n\n/**\n * Returns media title.\n *\n * @param {string} url\n * @param {object} props\n * @returns {string|null} String of media title.\n */\nexport const getMediaTitle = async(url, props) => {\n const extension = url.split('.').pop().split('?')[0];\n if (props.acceptedMediaTypes.includes(`.${extension}`)) {\n return getFileName(url);\n }\n\n return null;\n};\n\n/**\n * Return template context for media details.\n *\n * @param {object} props\n * @returns {object}\n */\nexport const mediaDetailsTemplateContext = async(props) => {\n const context = {\n bodyTemplate: Selectors.EMBED.template.body.mediaDetailsBody,\n footerTemplate: Selectors.EMBED.template.footer.mediaDetailsFooter,\n isLink: (props.mediaType === 'link'),\n isVideo: (props.mediaType === 'video'),\n showControl: (props.mediaType === 'video' || props.mediaType === 'audio'),\n isUpdating: props.isUpdating,\n isNewFileOrLinkUpload: (props.newMediaLink || props.newFileUpload),\n selector: Selectors.EMBED.type,\n };\n\n return {...context, ...props};\n};\n\n/**\n * Get help strings.\n *\n * @returns {object}\n */\nexport const getHelpStrings = async() => {\n const [\n subtitles,\n captions,\n descriptions,\n chapters,\n metadata,\n customsize,\n linkcustomsize,\n ] = await getStrings([\n 'subtitles_help',\n 'captions_help',\n 'descriptions_help',\n 'chapters_help',\n 'metadata_help',\n 'customsize_help',\n 'linkcustomsize_help',\n ].map((key) => ({\n key,\n component,\n })));\n\n return {\n subtitles,\n captions,\n descriptions,\n chapters,\n metadata,\n customsize,\n linkcustomsize,\n };\n};\n\n/**\n * Get current moodle languages.\n *\n * @param {editor} editor\n * @returns {object}\n */\nexport const prepareMoodleLang = (editor) => {\n const moodleLangs = getMoodleLang(editor);\n const currentLanguage = getCurrentLanguage(editor);\n\n const installed = Object.entries(moodleLangs.installed).map(([code, lang]) => ({\n lang,\n code,\n \"default\": code === currentLanguage,\n }));\n\n const available = Object.entries(moodleLangs.available).map(([code, lang]) => ({\n lang,\n code,\n \"default\": code === currentLanguage,\n }));\n\n return {\n installed,\n available,\n };\n};\n\n/**\n * Return moodle lang.\n *\n * @param {string} subtitleLang\n * @param {editor} editor\n * @returns {object|null}\n */\nexport const getMoodleLangObj = (subtitleLang, editor) => {\n const {available} = getMoodleLang(editor);\n\n if (available[subtitleLang]) {\n return {\n lang: subtitleLang,\n code: available[subtitleLang],\n };\n }\n\n return null;\n};\n\n/**\n * Get media data from the inserted media.\n *\n * @param {object} props\n * @returns {object}\n */\nexport const getEmbeddedMediaDetails = (props) => {\n const tracks = {\n subtitles: [],\n captions: [],\n descriptions: [],\n chapters: [],\n metadata: []\n };\n\n const mediaMetadata = props.root.querySelectorAll(Selectors.EMBED.elements.mediaMetadataTabPane);\n mediaMetadata.forEach(metaData => {\n const trackElements = metaData.querySelectorAll(Selectors.EMBED.elements.track);\n trackElements.forEach(track => {\n tracks[metaData.dataset.trackKind].push({\n src: track.querySelector(Selectors.EMBED.elements.url).value,\n srclang: track.querySelector(Selectors.EMBED.elements.trackLang).value,\n label: track.querySelector(Selectors.EMBED.elements.trackLabel).value,\n defaultTrack: track.querySelector(Selectors.EMBED.elements.trackDefault).checked,\n });\n });\n });\n\n const querySelector = (element) => props.root.querySelector(element);\n const mediaDataProps = {};\n mediaDataProps.media = {\n type: props.mediaType,\n sources: props.media,\n poster: props.media.poster ?? null,\n title: querySelector(Selectors.EMBED.elements.title).value,\n width: querySelector(Selectors.EMBED.elements.width).value,\n height: querySelector(Selectors.EMBED.elements.height).value,\n autoplay: querySelector(Selectors.EMBED.elements.mediaAutoplay).checked,\n loop: querySelector(Selectors.EMBED.elements.mediaLoop).checked,\n muted: querySelector(Selectors.EMBED.elements.mediaMute).checked,\n controls: querySelector(Selectors.EMBED.elements.mediaControl).checked,\n tracks,\n };\n mediaDataProps.link = false;\n return mediaDataProps;\n};\n\n/**\n * Check for video/audio attributes.\n *\n * @param {HTMLElement} elem\n * @param {string} attr Attribute name\n * @returns {boolean}\n */\nexport const hasAudioVideoAttr = (elem, attr) => {\n // As explained in MDL-64175, some OS (like Ubuntu), are removing the value for these attributes.\n // So in order to check if attr=\"true\", we need to check if the attribute exists and if the value is empty or true.\n return (elem.hasAttribute(attr) && (elem.getAttribute(attr) || elem.getAttribute(attr) === ''));\n};\n"],"names":["props","mediaType","showDropzone","canShowDropZone","showFilePicker","canShowFilePicker","fileType","elementid","editor","id","showImageFilePicker","canShowImageFilePicker","bodyTemplate","Selectors","EMBED","template","body","insertMediaBody","footerTemplate","footer","insertMediaFooter","selector","type","selectedMedia","mediaElm","selection","getNode","nodeName","toLowerCase","querySelector","async","url","contextId","request","methodname","args","contextid","content","Ajax","call","contentType","fetch","method","headers","get","startsWith","e","extension","split","pop","acceptedMediaTypes","includes","mediaDetailsBody","mediaDetailsFooter","isLink","isVideo","showControl","isUpdating","isNewFileOrLinkUpload","newMediaLink","newFileUpload","subtitles","captions","descriptions","chapters","metadata","customsize","linkcustomsize","map","key","component","moodleLangs","currentLanguage","installed","Object","entries","_ref","code","lang","available","_ref2","subtitleLang","tracks","root","querySelectorAll","elements","mediaMetadataTabPane","forEach","metaData","track","dataset","trackKind","push","src","value","srclang","trackLang","label","trackLabel","defaultTrack","trackDefault","checked","element","mediaDataProps","media","sources","poster","title","width","height","autoplay","mediaAutoplay","loop","mediaLoop","muted","mediaMute","controls","mediaControl","link","elem","attr","hasAttribute","getAttribute"],"mappings":"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"} \ No newline at end of file diff --git a/lib/editor/tiny/plugins/media/amd/build/embed/embedpreview.min.js b/lib/editor/tiny/plugins/media/amd/build/embed/embedpreview.min.js index 22cfb8f5d88..ae6a4c88a1d 100644 --- a/lib/editor/tiny/plugins/media/amd/build/embed/embedpreview.min.js +++ b/lib/editor/tiny/plugins/media/amd/build/embed/embedpreview.min.js @@ -1,3 +1,3 @@ -define("tiny_media/embed/embedpreview",["exports","../selectors","../common","core/str","../helpers","./embedhandler","../mediabase","core/notification","../embedmodal","./embedhelpers","core_filters/events"],(function(_exports,_selectors,_common,_str,_helpers,_embedhandler,_mediabase,_notification,_embedmodal,_embedhelpers,_events){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.EmbedPreview=void 0,_selectors=_interopRequireDefault(_selectors),_notification=_interopRequireDefault(_notification),_embedmodal=_interopRequireDefault(_embedmodal);class EmbedPreview extends _mediabase.MediaBase{constructor(data){super(),_defineProperty(this,"selectorType",_selectors.default.EMBED.type),_defineProperty(this,"linkMediaAspectRatio",1.78),_defineProperty(this,"init",(async()=>{var _this$fetchedMediaLin;this.currentModal.setTitle((0,_str.getString)("mediadetails",_common.component)),(0,_helpers.sourceTypeChecked)({fetchedTitle:null!==(_this$fetchedMediaLin=this.fetchedMediaLinkTitle)&&void 0!==_this$fetchedMediaLin?_this$fetchedMediaLin:null,source:this.originalUrl,root:this.root,urlSelector:_selectors.default.EMBED.elements.fromUrl,fileNameSelector:_selectors.default.EMBED.elements.fileNameLabel}),this.setMediaSourceAndPoster(),this.registerMediaDetailsEventListeners(this.currentModal)})),_defineProperty(this,"setMediaSourceAndPoster",(async()=>{const box=this.root.querySelector(_selectors.default.EMBED.elements.previewBox),previewArea=document.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer);if(previewArea.setAttribute("data-original-url",this.originalUrl),"link"===this.mediaType||this.newMediaLink&&!["video","audio"].includes(this.mediaType))previewArea.setAttribute("data-media-type","link"),previewArea.innerHTML=await(0,_embedhelpers.fetchPreview)(this.originalUrl,this.contextId),(0,_events.notifyFilterContentUpdated)(previewArea);else if("video"===this.mediaType){const video=document.createElement("video");video.src=this.originalUrl,video.addEventListener("loadedmetadata",(()=>{const videoHeight=video.videoHeight,videoWidth=video.videoWidth,isLandscape=videoWidth-videoHeight>0;this.mediaDimensions={width:videoWidth,height:videoHeight},isLandscape?video.width=box.offsetWidth:video.height=box.offsetHeight;const height=this.root.querySelector(_selectors.default.EMBED.elements.height),width=this.root.querySelector(_selectors.default.EMBED.elements.width);""===height.value&&""===width.value&&(height.value=videoHeight,width.value=videoWidth),videoHeight===parseInt(height.value)&&videoWidth===parseInt(width.value)?(this.currentWidth=this.mediaDimensions.width,this.currentHeight=this.mediaDimensions.height,this.sizeChecked("original")):(this.currentWidth=parseInt(width.value),this.currentHeight=parseInt(height.value),this.sizeChecked("custom"))})),video.controls=!0,this.media.poster&&(previewArea.setAttribute("data-media-poster",this.media.poster),video.classList.contains("w-100")||video.classList.add("w-100"),video.poster=this.media.poster),video.load(),previewArea.setAttribute("data-media-type","video"),previewArea.innerHTML=video.outerHTML,(0,_events.notifyFilterContentUpdated)(previewArea)}else{if("audio"!==this.mediaType){return this.root.querySelector(_selectors.default.EMBED.elements.urlWarning).innerHTML=await(0,_str.getString)("medianotavailabledesc",_common.component,this.originalUrl),(0,_helpers.showElements)(_selectors.default.EMBED.elements.urlWarning,this.root),(0,_helpers.stopMediaLoading)(this.root,_selectors.default.EMBED.type),void new _embedhandler.EmbedHandler(this).resetUploadForm()}{const audio=document.createElement("audio");audio.src=this.originalUrl,audio.controls=!0,audio.load(),previewArea.setAttribute("data-media-type","audio"),previewArea.innerHTML=audio.outerHTML,(0,_events.notifyFilterContentUpdated)(previewArea)}}(0,_helpers.stopMediaLoading)(this.root,_selectors.default.EMBED.type),(0,_helpers.showElements)(_selectors.default.EMBED.elements.mediaDetailsBody,this.root),this.root.querySelector(_selectors.default.EMBED.elements.title).value=this.setMediaTitle()})),_defineProperty(this,"setMediaTitle",(()=>{let fileName=null;return fileName=["video","audio"].includes(this.mediaType)?(0,_helpers.getFileName)(this.originalUrl):this.fetchedMediaLinkTitle?this.fetchedMediaLinkTitle:this.originalUrl,this.isUpdating&&(this.newMediaLink||(fileName=this.mediaTitle)),fileName})),_defineProperty(this,"deleteMedia",(()=>{_notification.default.deleteCancelPromise((0,_str.getString)("deletemedia",_common.component),(0,_str.getString)("deletemediawarning",_common.component)).then((()=>{new _embedhandler.EmbedHandler(this).resetUploadForm(),delete this.mediaData})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"deleteEmbeddedThumbnail",(()=>{_notification.default.deleteCancelPromise((0,_str.getString)("deleteembeddedthumbnail",_common.component),(0,_str.getString)("deleteembeddedthumbnailwarning",_common.component)).then((async()=>{if("video"===this.mediaType){const video=this.root.querySelector("video");if(video){video.removeAttribute("poster");this.root.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer).removeAttribute("data-media-poster")}}this.root.querySelector(_selectors.default.EMBED.actions.deleteCustomThumbnail).remove();this.root.querySelector(_selectors.default.EMBED.actions.uploadCustomThumbnail).textContent=await(0,_str.getString)("uploadthumbnail",_common.component)})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"showUploadThumbnail",(async()=>{const uploadThumbnailModal=await _embedmodal.default.create({large:!0,templateContext:{elementid:this.editor.getElement().id}}),root=uploadThumbnailModal.getRoot()[0],mediaData=(0,_embedhelpers.getEmbeddedMediaDetails)(this);mediaData.isUpdating=this.isUpdating;const embedHandler=new _embedhandler.EmbedHandler(this);embedHandler.loadInsertThumbnailTemplatePromise((0,_embedhelpers.insertMediaThumbnailTemplateContext)(this),{root:root,uploadThumbnailModal:uploadThumbnailModal},await embedHandler.getMediaTemplateContext(mediaData))})),_defineProperty(this,"registerMediaDetailsEventListeners",(async()=>{const sizeOriginalEle=this.root.querySelector(_selectors.default.EMBED.elements.sizeOriginal);sizeOriginalEle&&sizeOriginalEle.addEventListener("change",(()=>{this.sizeChecked("original")}));const sizeCustomEle=this.root.querySelector(_selectors.default.EMBED.elements.sizeCustom);sizeCustomEle&&sizeCustomEle.addEventListener("change",(()=>{this.sizeChecked("custom")}));const widthEle=this.root.querySelector(_selectors.default.EMBED.elements.width),heightEle=this.root.querySelector(_selectors.default.EMBED.elements.height);widthEle&&widthEle.addEventListener("input",(()=>{"link"===this.mediaType?heightEle.value=Math.round(widthEle.value/this.linkMediaAspectRatio):(widthEle.value=""===widthEle.value?0:Number(widthEle.value),this.autoAdjustSize())})),heightEle&&heightEle.addEventListener("input",(()=>{"link"===this.mediaType?widthEle.value=Math.round(heightEle.value*this.linkMediaAspectRatio):(heightEle.value=""===heightEle.value?0:Number(heightEle.value),this.autoAdjustSize(!0))}));const deleteMedia=this.root.querySelector(_selectors.default.EMBED.actions.deleteMedia);deleteMedia&&deleteMedia.addEventListener("click",(e=>{e.preventDefault(),this.deleteMedia()}));const showSubtitleCaption=this.root.querySelector(_selectors.default.EMBED.actions.showSubtitleCaption);showSubtitleCaption&&showSubtitleCaption.addEventListener("click",(e=>{e.preventDefault(),(0,_helpers.hideElements)([_selectors.default.EMBED.actions.showSubtitleCaption,_selectors.default.EMBED.actions.cancelMediaDetails,_selectors.default.EMBED.elements.mediaDetailsBody],this.root),(0,_helpers.showElements)([_selectors.default.EMBED.actions.backToMediaDetails,_selectors.default.EMBED.elements.mediaSubtitleCaptionBody],this.root)}));const backToMediaDetails=this.root.querySelector(_selectors.default.EMBED.actions.backToMediaDetails);backToMediaDetails&&backToMediaDetails.addEventListener("click",(()=>{(0,_helpers.hideElements)([_selectors.default.EMBED.actions.backToMediaDetails,_selectors.default.EMBED.elements.mediaSubtitleCaptionBody],this.root),(0,_helpers.showElements)([_selectors.default.EMBED.actions.showSubtitleCaption,_selectors.default.EMBED.actions.cancelMediaDetails,_selectors.default.EMBED.elements.mediaDetailsBody],this.root)}));const uploadCustomThumbnail=this.root.querySelector(_selectors.default.EMBED.actions.uploadCustomThumbnail);uploadCustomThumbnail&&uploadCustomThumbnail.addEventListener("click",(()=>{this.showUploadThumbnail()}));const deleteCustomThumbnail=this.root.querySelector(_selectors.default.EMBED.actions.deleteCustomThumbnail);deleteCustomThumbnail&&deleteCustomThumbnail.addEventListener("click",(()=>{this.deleteEmbeddedThumbnail()}));const langTracks=this.root.querySelectorAll(_selectors.default.EMBED.elements.trackLang);langTracks&&langTracks.forEach((dropdown=>{const defaultVal=dropdown.getAttribute("data-value");defaultVal&&(dropdown.value=defaultVal)}))})),(0,_helpers.setPropertiesFromData)(this,data)}}_exports.EmbedPreview=EmbedPreview})); +define("tiny_media/embed/embedpreview",["exports","../selectors","../common","core/str","../helpers","./embedhandler","../mediabase","core/notification","../embedmodal","./embedhelpers","core_filters/events"],(function(_exports,_selectors,_common,_str,_helpers,_embedhandler,_mediabase,_notification,_embedmodal,_embedhelpers,_events){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.EmbedPreview=void 0,_selectors=_interopRequireDefault(_selectors),_notification=_interopRequireDefault(_notification),_embedmodal=_interopRequireDefault(_embedmodal);class EmbedPreview extends _mediabase.MediaBase{constructor(data){super(),_defineProperty(this,"selectorType",_selectors.default.EMBED.type),_defineProperty(this,"linkMediaAspectRatio",1.78),_defineProperty(this,"init",(async()=>{var _this$fetchedMediaLin;this.currentModal.setTitle((0,_str.getString)("mediadetails",_common.component)),(0,_helpers.sourceTypeChecked)({fetchedTitle:null!==(_this$fetchedMediaLin=this.fetchedMediaLinkTitle)&&void 0!==_this$fetchedMediaLin?_this$fetchedMediaLin:null,source:this.originalUrl,root:this.root,urlSelector:_selectors.default.EMBED.elements.fromUrl,fileNameSelector:_selectors.default.EMBED.elements.fileNameLabel}),this.setMediaSourceAndPoster(),this.registerMediaDetailsEventListeners(this.currentModal)})),_defineProperty(this,"setMediaSourceAndPoster",(async()=>{const box=this.root.querySelector(_selectors.default.EMBED.elements.previewBox),previewArea=document.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer);if(previewArea.setAttribute("data-original-url",this.originalUrl),"link"===this.mediaType||this.newMediaLink&&!["video","audio"].includes(this.mediaType))previewArea.setAttribute("data-media-type","link"),previewArea.innerHTML=await(0,_embedhelpers.fetchPreview)(this.originalUrl,this.contextId),(0,_events.notifyFilterContentUpdated)(previewArea);else if("video"===this.mediaType){const video=document.createElement("video");video.src=this.originalUrl,video.addEventListener("loadedmetadata",(()=>{const videoHeight=video.videoHeight,videoWidth=video.videoWidth,isLandscape=videoWidth-videoHeight>0;this.mediaDimensions={width:videoWidth,height:videoHeight},isLandscape?video.width=box.offsetWidth:video.height=box.offsetHeight;const height=this.root.querySelector(_selectors.default.EMBED.elements.height),width=this.root.querySelector(_selectors.default.EMBED.elements.width);""===height.value&&""===width.value&&(height.value=videoHeight,width.value=videoWidth),videoHeight===parseInt(height.value)&&videoWidth===parseInt(width.value)?(this.currentWidth=this.mediaDimensions.width,this.currentHeight=this.mediaDimensions.height,this.sizeChecked("original")):(this.currentWidth=parseInt(width.value),this.currentHeight=parseInt(height.value),this.sizeChecked("custom"))})),video.controls=!0,this.media.poster&&(previewArea.setAttribute("data-media-poster",this.media.poster),video.classList.contains("w-100")||video.classList.add("w-100"),video.poster=this.media.poster),video.load(),previewArea.setAttribute("data-media-type","video"),previewArea.innerHTML=video.outerHTML,(0,_events.notifyFilterContentUpdated)(previewArea)}else{if("audio"!==this.mediaType){return this.root.querySelector(_selectors.default.EMBED.elements.urlWarning).innerHTML=await(0,_str.getString)("medianotavailabledesc",_common.component,this.originalUrl),(0,_helpers.showElements)(_selectors.default.EMBED.elements.urlWarning,this.root),(0,_helpers.stopMediaLoading)(this.root,_selectors.default.EMBED.type),void new _embedhandler.EmbedHandler(this).resetUploadForm()}{const audio=document.createElement("audio");audio.src=this.originalUrl,audio.controls=!0,audio.load(),previewArea.setAttribute("data-media-type","audio"),previewArea.innerHTML=audio.outerHTML,(0,_events.notifyFilterContentUpdated)(previewArea)}}(0,_helpers.stopMediaLoading)(this.root,_selectors.default.EMBED.type),(0,_helpers.showElements)(_selectors.default.EMBED.elements.mediaDetailsBody,this.root),this.root.querySelector(_selectors.default.EMBED.elements.title).value=this.setMediaTitle()})),_defineProperty(this,"setMediaTitle",(()=>{let fileName=null;return fileName=["video","audio"].includes(this.mediaType)?(0,_helpers.getFileName)(this.originalUrl):this.fetchedMediaLinkTitle?this.fetchedMediaLinkTitle:this.originalUrl,this.isUpdating&&(this.newMediaLink||(fileName=this.mediaTitle)),fileName})),_defineProperty(this,"deleteMedia",(()=>{_notification.default.deleteCancelPromise((0,_str.getString)("deletemedia",_common.component),(0,_str.getString)("deletemediawarning",_common.component)).then((()=>{new _embedhandler.EmbedHandler(this).resetUploadForm(),delete this.mediaData})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"deleteEmbeddedThumbnail",(()=>{_notification.default.deleteCancelPromise((0,_str.getString)("deleteembeddedthumbnail",_common.component),(0,_str.getString)("deleteembeddedthumbnailwarning",_common.component)).then((async()=>{if("video"===this.mediaType){const video=this.root.querySelector("video");if(video){video.removeAttribute("poster");this.root.querySelector(_selectors.default.EMBED.elements.mediaPreviewContainer).removeAttribute("data-media-poster")}}this.root.querySelector(_selectors.default.EMBED.actions.deleteCustomThumbnail).remove();this.root.querySelector(_selectors.default.EMBED.actions.uploadCustomThumbnail).textContent=await(0,_str.getString)("uploadthumbnail",_common.component)})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"showUploadThumbnail",(async()=>{const uploadThumbnailModal=await _embedmodal.default.create({large:!0,templateContext:{elementid:this.editor.getElement().id}}),root=uploadThumbnailModal.getRoot()[0],mediaData=(0,_embedhelpers.getEmbeddedMediaDetails)(this);mediaData.isUpdating=this.isUpdating;const embedHandler=new _embedhandler.EmbedHandler(this);embedHandler.loadInsertThumbnailTemplatePromise((0,_embedhelpers.insertMediaThumbnailTemplateContext)(this),{root:root,uploadThumbnailModal:uploadThumbnailModal},await embedHandler.getMediaTemplateContext(mediaData))})),_defineProperty(this,"registerMediaDetailsEventListeners",(async()=>{const sizeOriginalEle=this.root.querySelector(_selectors.default.EMBED.elements.sizeOriginal);sizeOriginalEle&&sizeOriginalEle.addEventListener("change",(()=>{this.sizeChecked("original")}));const sizeCustomEle=this.root.querySelector(_selectors.default.EMBED.elements.sizeCustom);sizeCustomEle&&sizeCustomEle.addEventListener("change",(()=>{this.sizeChecked("custom")}));const widthEle=this.root.querySelector(_selectors.default.EMBED.elements.width),heightEle=this.root.querySelector(_selectors.default.EMBED.elements.height);widthEle&&widthEle.addEventListener("input",(()=>{"link"===this.mediaType?heightEle.value=Math.round(widthEle.value/this.linkMediaAspectRatio):(widthEle.value=""===widthEle.value?0:Number(widthEle.value),this.autoAdjustSize())})),heightEle&&heightEle.addEventListener("input",(()=>{"link"===this.mediaType?widthEle.value=Math.round(heightEle.value*this.linkMediaAspectRatio):(heightEle.value=""===heightEle.value?0:Number(heightEle.value),this.autoAdjustSize(!0))}));const deleteMedia=this.root.querySelector(_selectors.default.EMBED.actions.deleteMedia);deleteMedia&&deleteMedia.addEventListener("click",(e=>{e.preventDefault(),this.deleteMedia()}));const showSubtitleCaption=this.root.querySelector(_selectors.default.EMBED.actions.showSubtitleCaption);showSubtitleCaption&&showSubtitleCaption.addEventListener("click",(e=>{e.preventDefault(),(0,_helpers.hideElements)([_selectors.default.EMBED.actions.showSubtitleCaption,_selectors.default.EMBED.actions.cancelMediaDetails,_selectors.default.EMBED.elements.mediaDetailsBody],this.root),(0,_helpers.showElements)([_selectors.default.EMBED.actions.backToMediaDetails,_selectors.default.EMBED.elements.mediaSubtitleCaptionBody],this.root)}));const backToMediaDetails=this.root.querySelector(_selectors.default.EMBED.actions.backToMediaDetails);backToMediaDetails&&backToMediaDetails.addEventListener("click",(()=>{(0,_helpers.hideElements)([_selectors.default.EMBED.actions.backToMediaDetails,_selectors.default.EMBED.elements.mediaSubtitleCaptionBody],this.root),(0,_helpers.showElements)([_selectors.default.EMBED.actions.showSubtitleCaption,_selectors.default.EMBED.actions.cancelMediaDetails,_selectors.default.EMBED.elements.mediaDetailsBody],this.root)}));const uploadCustomThumbnail=this.root.querySelector(_selectors.default.EMBED.actions.uploadCustomThumbnail);uploadCustomThumbnail&&uploadCustomThumbnail.addEventListener("click",(()=>{this.showUploadThumbnail()}));const deleteCustomThumbnail=this.root.querySelector(_selectors.default.EMBED.actions.deleteCustomThumbnail);deleteCustomThumbnail&&deleteCustomThumbnail.addEventListener("click",(()=>{this.deleteEmbeddedThumbnail()}));const langTracks=this.root.querySelectorAll(_selectors.default.EMBED.elements.trackLang);langTracks&&langTracks.forEach((dropdown=>{const defaultVal=dropdown.getAttribute("data-value");if(defaultVal)if(2===defaultVal.length){const options=dropdown.options;for(let i=0;i.\n\n/**\n * Tiny media plugin embed preview and details class.\n *\n * This handles the embed file/url preview before embedding them into tiny editor.\n *\n * @module tiny_media/embed/embedpreview\n * @copyright 2024 Stevani Andolo \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from '../selectors';\nimport {component} from '../common';\nimport {getString} from 'core/str';\nimport {\n sourceTypeChecked,\n getFileName,\n setPropertiesFromData,\n showElements,\n stopMediaLoading,\n hideElements,\n} from '../helpers';\nimport {EmbedHandler} from './embedhandler';\nimport {MediaBase} from '../mediabase';\nimport Notification from 'core/notification';\nimport EmbedModal from '../embedmodal';\nimport {\n getEmbeddedMediaDetails,\n insertMediaThumbnailTemplateContext,\n fetchPreview,\n} from './embedhelpers';\nimport {notifyFilterContentUpdated} from 'core_filters/events';\n\nexport class EmbedPreview extends MediaBase {\n\n // Selector type for \"EMBED\".\n selectorType = Selectors.EMBED.type;\n\n // Fixed aspect ratio used for external media providers.\n linkMediaAspectRatio = 1.78;\n\n constructor(data) {\n super();\n setPropertiesFromData(this, data); // Creates dynamic properties based on \"data\" param.\n }\n\n /**\n * Init the media details preview.\n */\n init = async() => {\n this.currentModal.setTitle(getString('mediadetails', component));\n sourceTypeChecked({\n fetchedTitle: this.fetchedMediaLinkTitle ?? null,\n source: this.originalUrl,\n root: this.root,\n urlSelector: Selectors.EMBED.elements.fromUrl,\n fileNameSelector: Selectors.EMBED.elements.fileNameLabel,\n });\n this.setMediaSourceAndPoster();\n this.registerMediaDetailsEventListeners(this.currentModal);\n };\n\n /**\n * Sets media source and thumbnail for the video.\n */\n setMediaSourceAndPoster = async() => {\n const box = this.root.querySelector(Selectors.EMBED.elements.previewBox);\n const previewArea = document.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n previewArea.setAttribute('data-original-url', this.originalUrl);\n\n // Previewing existing media could be a link one.\n // Or, new media added using url input and mediaType is neither video or audio.\n if (this.mediaType === 'link' || (this.newMediaLink && !['video', 'audio'].includes(this.mediaType))) {\n previewArea.setAttribute('data-media-type', 'link');\n previewArea.innerHTML = await fetchPreview(this.originalUrl, this.contextId);\n notifyFilterContentUpdated(previewArea);\n } else if (this.mediaType === 'video') {\n const video = document.createElement('video');\n video.src = this.originalUrl;\n\n // Media url can be played using html video.\n video.addEventListener('loadedmetadata', () => {\n const videoHeight = video.videoHeight;\n const videoWidth = video.videoWidth;\n const widthProportion = (videoWidth - videoHeight);\n const isLandscape = widthProportion > 0;\n\n // Store dimensions of the raw video.\n this.mediaDimensions = {\n width: videoWidth,\n height: videoHeight,\n };\n\n // Set the media preview based on the media dimensions.\n if (isLandscape) {\n video.width = box.offsetWidth;\n } else {\n video.height = box.offsetHeight;\n }\n\n const height = this.root.querySelector(Selectors.EMBED.elements.height);\n const width = this.root.querySelector(Selectors.EMBED.elements.width);\n\n if (height.value === '' && width.value === '') {\n height.value = videoHeight;\n width.value = videoWidth;\n }\n\n // Size checking and adjustment.\n if (videoHeight === parseInt(height.value) && videoWidth === parseInt(width.value)) {\n this.currentWidth = this.mediaDimensions.width;\n this.currentHeight = this.mediaDimensions.height;\n this.sizeChecked('original');\n } else {\n this.currentWidth = parseInt(width.value);\n this.currentHeight = parseInt(height.value);\n this.sizeChecked('custom');\n }\n });\n\n video.controls = true;\n if (this.media.poster) {\n previewArea.setAttribute('data-media-poster', this.media.poster);\n if (!video.classList.contains('w-100')) {\n video.classList.add('w-100');\n }\n video.poster = this.media.poster;\n }\n video.load();\n\n previewArea.setAttribute('data-media-type', 'video');\n previewArea.innerHTML = video.outerHTML;\n notifyFilterContentUpdated(previewArea);\n } else if (this.mediaType === 'audio') {\n const audio = document.createElement('audio');\n audio.src = this.originalUrl;\n audio.controls = true;\n audio.load();\n\n previewArea.setAttribute('data-media-type', 'audio');\n previewArea.innerHTML = audio.outerHTML;\n notifyFilterContentUpdated(previewArea);\n } else {\n // Show warning notification.\n const urlWarningLabelEle = this.root.querySelector(Selectors.EMBED.elements.urlWarning);\n urlWarningLabelEle.innerHTML = await getString('medianotavailabledesc', component, this.originalUrl);\n showElements(Selectors.EMBED.elements.urlWarning, this.root);\n\n // Stop the spinner.\n stopMediaLoading(this.root, Selectors.EMBED.type);\n\n // Reset the upload form.\n (new EmbedHandler(this)).resetUploadForm();\n return;\n }\n\n // Stop the loader and display back the body template when the media is loaded.\n stopMediaLoading(this.root, Selectors.EMBED.type);\n showElements(Selectors.EMBED.elements.mediaDetailsBody, this.root);\n\n // Set the media name/title.\n this.root.querySelector(Selectors.EMBED.elements.title).value = this.setMediaTitle();\n };\n\n /**\n * Set media name/title.\n *\n * @returns {string}\n */\n setMediaTitle = () => {\n // Getting and setting up media title/name.\n let fileName = null;\n if (['video', 'audio'].includes(this.mediaType)) {\n fileName = getFileName(this.originalUrl); // Get original filename.\n } else if (this.fetchedMediaLinkTitle) {\n fileName = this.fetchedMediaLinkTitle;\n } else {\n fileName = this.originalUrl;\n }\n\n if (this.isUpdating) {\n if (!this.newMediaLink) {\n fileName = this.mediaTitle; // Title from the selected media.\n }\n }\n\n return fileName;\n };\n\n /**\n * Deletes the media after confirming with the user and loads the insert media page.\n */\n deleteMedia = () => {\n Notification.deleteCancelPromise(\n getString('deletemedia', component),\n getString('deletemediawarning', component),\n ).then(() => {\n // Reset media upload form.\n (new EmbedHandler(this)).resetUploadForm();\n\n // Delete any selected media mediaData.\n delete this.mediaData;\n return;\n }).catch(error => {\n window.console.log(error);\n });\n };\n\n /**\n * Delete embedded media thumbnail.\n */\n deleteEmbeddedThumbnail = () => {\n Notification.deleteCancelPromise(\n getString('deleteembeddedthumbnail', component),\n getString('deleteembeddedthumbnailwarning', component),\n ).then(async() => {\n if (this.mediaType === 'video') {\n const video = this.root.querySelector('video');\n if (video) {\n video.removeAttribute('poster');\n const preview = this.root.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n preview.removeAttribute('data-media-poster');\n }\n }\n\n const deleteCustomThumbnail = this.root.querySelector(Selectors.EMBED.actions.deleteCustomThumbnail);\n deleteCustomThumbnail.remove();\n\n const uploadCustomThumbnail = this.root.querySelector(Selectors.EMBED.actions.uploadCustomThumbnail);\n uploadCustomThumbnail.textContent = await getString('uploadthumbnail', component);\n return;\n }).catch(error => {\n window.console.log(error);\n });\n };\n\n /**\n * Shows the insert thumbnail dialogue.\n */\n showUploadThumbnail = async() => {\n const uploadThumbnailModal = await EmbedModal.create({\n large: true,\n templateContext: {elementid: this.editor.getElement().id},\n });\n const root = uploadThumbnailModal.getRoot()[0];\n\n // Get selected media metadata.\n const mediaData = getEmbeddedMediaDetails(this);\n mediaData.isUpdating = this.isUpdating;\n\n const embedHandler = new EmbedHandler(this);\n embedHandler.loadInsertThumbnailTemplatePromise(\n insertMediaThumbnailTemplateContext(this), // Get template context for creating media thumbnail.\n {root, uploadThumbnailModal}, // Required root elements.\n await embedHandler.getMediaTemplateContext(mediaData) // Get current media data.\n );\n };\n\n /**\n * Only registers event listeners for new loaded elements in embed preview modal.\n */\n registerMediaDetailsEventListeners = async() => {\n // Handle the original size when selected.\n const sizeOriginalEle = this.root.querySelector(Selectors.EMBED.elements.sizeOriginal);\n if (sizeOriginalEle) {\n sizeOriginalEle.addEventListener('change', () => {\n this.sizeChecked('original');\n });\n }\n\n // Handle the custom size when selected.\n const sizeCustomEle = this.root.querySelector(Selectors.EMBED.elements.sizeCustom);\n if (sizeCustomEle) {\n sizeCustomEle.addEventListener('change', () => {\n this.sizeChecked('custom');\n });\n }\n\n const widthEle = this.root.querySelector(Selectors.EMBED.elements.width);\n const heightEle = this.root.querySelector(Selectors.EMBED.elements.height);\n\n // Handle the custom with size when inputted.\n if (widthEle) {\n widthEle.addEventListener('input', () => {\n if (this.mediaType === 'link') {\n // Let's apply the 16:9 aspect ratio if it's a link media type.\n heightEle.value = Math.round(widthEle.value / this.linkMediaAspectRatio);\n } else {\n // Avoid empty value.\n widthEle.value = widthEle.value === \"\" ? 0 : Number(widthEle.value);\n this.autoAdjustSize();\n }\n });\n }\n\n // Handle the custom height size when inputted.\n if (heightEle) {\n heightEle.addEventListener('input', () => {\n if (this.mediaType === 'link') {\n // Let's apply the 16:9 aspect ratio if it's a link media type.\n widthEle.value = Math.round(heightEle.value * this.linkMediaAspectRatio);\n } else {\n // Avoid empty value.\n heightEle.value = heightEle.value === \"\" ? 0 : Number(heightEle.value);\n this.autoAdjustSize(true);\n }\n });\n }\n\n // Handle media preview delete.\n const deleteMedia = this.root.querySelector(Selectors.EMBED.actions.deleteMedia);\n if (deleteMedia) {\n deleteMedia.addEventListener('click', (e) => {\n e.preventDefault();\n this.deleteMedia();\n });\n }\n\n // Show subtitles and captions settings.\n const showSubtitleCaption = this.root.querySelector(Selectors.EMBED.actions.showSubtitleCaption);\n if (showSubtitleCaption) {\n showSubtitleCaption.addEventListener('click', (e) => {\n e.preventDefault();\n hideElements([\n Selectors.EMBED.actions.showSubtitleCaption,\n Selectors.EMBED.actions.cancelMediaDetails,\n Selectors.EMBED.elements.mediaDetailsBody,\n ], this.root);\n showElements([\n Selectors.EMBED.actions.backToMediaDetails,\n Selectors.EMBED.elements.mediaSubtitleCaptionBody,\n ], this.root);\n });\n }\n\n // Back to media preview.\n const backToMediaDetails = this.root.querySelector(Selectors.EMBED.actions.backToMediaDetails);\n if (backToMediaDetails) {\n backToMediaDetails.addEventListener('click', () => {\n hideElements([\n Selectors.EMBED.actions.backToMediaDetails,\n Selectors.EMBED.elements.mediaSubtitleCaptionBody,\n ], this.root);\n showElements([\n Selectors.EMBED.actions.showSubtitleCaption,\n Selectors.EMBED.actions.cancelMediaDetails,\n Selectors.EMBED.elements.mediaDetailsBody,\n ], this.root);\n });\n }\n\n // Handles upload media thumbnail.\n const uploadCustomThumbnail = this.root.querySelector(Selectors.EMBED.actions.uploadCustomThumbnail);\n if (uploadCustomThumbnail) {\n uploadCustomThumbnail.addEventListener('click', () => {\n this.showUploadThumbnail();\n });\n }\n\n // Handles delete media thumbnail.\n const deleteCustomThumbnail = this.root.querySelector(Selectors.EMBED.actions.deleteCustomThumbnail);\n if (deleteCustomThumbnail) {\n deleteCustomThumbnail.addEventListener('click', () => {\n this.deleteEmbeddedThumbnail();\n });\n }\n\n // Handles language track selection.\n const langTracks = this.root.querySelectorAll(Selectors.EMBED.elements.trackLang);\n if (langTracks) {\n langTracks.forEach((dropdown) => {\n const defaultVal = dropdown.getAttribute('data-value');\n if (defaultVal) {\n dropdown.value = defaultVal;\n }\n });\n }\n };\n}\n"],"names":["EmbedPreview","MediaBase","constructor","data","Selectors","EMBED","type","async","currentModal","setTitle","component","fetchedTitle","this","fetchedMediaLinkTitle","source","originalUrl","root","urlSelector","elements","fromUrl","fileNameSelector","fileNameLabel","setMediaSourceAndPoster","registerMediaDetailsEventListeners","box","querySelector","previewBox","previewArea","document","mediaPreviewContainer","setAttribute","mediaType","newMediaLink","includes","innerHTML","contextId","video","createElement","src","addEventListener","videoHeight","videoWidth","isLandscape","mediaDimensions","width","height","offsetWidth","offsetHeight","value","parseInt","currentWidth","currentHeight","sizeChecked","controls","media","poster","classList","contains","add","load","outerHTML","urlWarning","EmbedHandler","resetUploadForm","audio","mediaDetailsBody","title","setMediaTitle","fileName","isUpdating","mediaTitle","deleteCancelPromise","then","mediaData","catch","error","window","console","log","removeAttribute","actions","deleteCustomThumbnail","remove","uploadCustomThumbnail","textContent","uploadThumbnailModal","EmbedModal","create","large","templateContext","elementid","editor","getElement","id","getRoot","embedHandler","loadInsertThumbnailTemplatePromise","getMediaTemplateContext","sizeOriginalEle","sizeOriginal","sizeCustomEle","sizeCustom","widthEle","heightEle","Math","round","linkMediaAspectRatio","Number","autoAdjustSize","deleteMedia","e","preventDefault","showSubtitleCaption","cancelMediaDetails","backToMediaDetails","mediaSubtitleCaptionBody","showUploadThumbnail","deleteEmbeddedThumbnail","langTracks","querySelectorAll","trackLang","forEach","dropdown","defaultVal","getAttribute"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"embedpreview.min.js","sources":["../../src/embed/embedpreview.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 embed preview and details class.\n *\n * This handles the embed file/url preview before embedding them into tiny editor.\n *\n * @module tiny_media/embed/embedpreview\n * @copyright 2024 Stevani Andolo \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from '../selectors';\nimport {component} from '../common';\nimport {getString} from 'core/str';\nimport {\n sourceTypeChecked,\n getFileName,\n setPropertiesFromData,\n showElements,\n stopMediaLoading,\n hideElements,\n} from '../helpers';\nimport {EmbedHandler} from './embedhandler';\nimport {MediaBase} from '../mediabase';\nimport Notification from 'core/notification';\nimport EmbedModal from '../embedmodal';\nimport {\n getEmbeddedMediaDetails,\n insertMediaThumbnailTemplateContext,\n fetchPreview,\n} from './embedhelpers';\nimport {notifyFilterContentUpdated} from 'core_filters/events';\n\nexport class EmbedPreview extends MediaBase {\n\n // Selector type for \"EMBED\".\n selectorType = Selectors.EMBED.type;\n\n // Fixed aspect ratio used for external media providers.\n linkMediaAspectRatio = 1.78;\n\n constructor(data) {\n super();\n setPropertiesFromData(this, data); // Creates dynamic properties based on \"data\" param.\n }\n\n /**\n * Init the media details preview.\n */\n init = async() => {\n this.currentModal.setTitle(getString('mediadetails', component));\n sourceTypeChecked({\n fetchedTitle: this.fetchedMediaLinkTitle ?? null,\n source: this.originalUrl,\n root: this.root,\n urlSelector: Selectors.EMBED.elements.fromUrl,\n fileNameSelector: Selectors.EMBED.elements.fileNameLabel,\n });\n this.setMediaSourceAndPoster();\n this.registerMediaDetailsEventListeners(this.currentModal);\n };\n\n /**\n * Sets media source and thumbnail for the video.\n */\n setMediaSourceAndPoster = async() => {\n const box = this.root.querySelector(Selectors.EMBED.elements.previewBox);\n const previewArea = document.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n previewArea.setAttribute('data-original-url', this.originalUrl);\n\n // Previewing existing media could be a link one.\n // Or, new media added using url input and mediaType is neither video or audio.\n if (this.mediaType === 'link' || (this.newMediaLink && !['video', 'audio'].includes(this.mediaType))) {\n previewArea.setAttribute('data-media-type', 'link');\n previewArea.innerHTML = await fetchPreview(this.originalUrl, this.contextId);\n notifyFilterContentUpdated(previewArea);\n } else if (this.mediaType === 'video') {\n const video = document.createElement('video');\n video.src = this.originalUrl;\n\n // Media url can be played using html video.\n video.addEventListener('loadedmetadata', () => {\n const videoHeight = video.videoHeight;\n const videoWidth = video.videoWidth;\n const widthProportion = (videoWidth - videoHeight);\n const isLandscape = widthProportion > 0;\n\n // Store dimensions of the raw video.\n this.mediaDimensions = {\n width: videoWidth,\n height: videoHeight,\n };\n\n // Set the media preview based on the media dimensions.\n if (isLandscape) {\n video.width = box.offsetWidth;\n } else {\n video.height = box.offsetHeight;\n }\n\n const height = this.root.querySelector(Selectors.EMBED.elements.height);\n const width = this.root.querySelector(Selectors.EMBED.elements.width);\n\n if (height.value === '' && width.value === '') {\n height.value = videoHeight;\n width.value = videoWidth;\n }\n\n // Size checking and adjustment.\n if (videoHeight === parseInt(height.value) && videoWidth === parseInt(width.value)) {\n this.currentWidth = this.mediaDimensions.width;\n this.currentHeight = this.mediaDimensions.height;\n this.sizeChecked('original');\n } else {\n this.currentWidth = parseInt(width.value);\n this.currentHeight = parseInt(height.value);\n this.sizeChecked('custom');\n }\n });\n\n video.controls = true;\n if (this.media.poster) {\n previewArea.setAttribute('data-media-poster', this.media.poster);\n if (!video.classList.contains('w-100')) {\n video.classList.add('w-100');\n }\n video.poster = this.media.poster;\n }\n video.load();\n\n previewArea.setAttribute('data-media-type', 'video');\n previewArea.innerHTML = video.outerHTML;\n notifyFilterContentUpdated(previewArea);\n } else if (this.mediaType === 'audio') {\n const audio = document.createElement('audio');\n audio.src = this.originalUrl;\n audio.controls = true;\n audio.load();\n\n previewArea.setAttribute('data-media-type', 'audio');\n previewArea.innerHTML = audio.outerHTML;\n notifyFilterContentUpdated(previewArea);\n } else {\n // Show warning notification.\n const urlWarningLabelEle = this.root.querySelector(Selectors.EMBED.elements.urlWarning);\n urlWarningLabelEle.innerHTML = await getString('medianotavailabledesc', component, this.originalUrl);\n showElements(Selectors.EMBED.elements.urlWarning, this.root);\n\n // Stop the spinner.\n stopMediaLoading(this.root, Selectors.EMBED.type);\n\n // Reset the upload form.\n (new EmbedHandler(this)).resetUploadForm();\n return;\n }\n\n // Stop the loader and display back the body template when the media is loaded.\n stopMediaLoading(this.root, Selectors.EMBED.type);\n showElements(Selectors.EMBED.elements.mediaDetailsBody, this.root);\n\n // Set the media name/title.\n this.root.querySelector(Selectors.EMBED.elements.title).value = this.setMediaTitle();\n };\n\n /**\n * Set media name/title.\n *\n * @returns {string}\n */\n setMediaTitle = () => {\n // Getting and setting up media title/name.\n let fileName = null;\n if (['video', 'audio'].includes(this.mediaType)) {\n fileName = getFileName(this.originalUrl); // Get original filename.\n } else if (this.fetchedMediaLinkTitle) {\n fileName = this.fetchedMediaLinkTitle;\n } else {\n fileName = this.originalUrl;\n }\n\n if (this.isUpdating) {\n if (!this.newMediaLink) {\n fileName = this.mediaTitle; // Title from the selected media.\n }\n }\n\n return fileName;\n };\n\n /**\n * Deletes the media after confirming with the user and loads the insert media page.\n */\n deleteMedia = () => {\n Notification.deleteCancelPromise(\n getString('deletemedia', component),\n getString('deletemediawarning', component),\n ).then(() => {\n // Reset media upload form.\n (new EmbedHandler(this)).resetUploadForm();\n\n // Delete any selected media mediaData.\n delete this.mediaData;\n return;\n }).catch(error => {\n window.console.log(error);\n });\n };\n\n /**\n * Delete embedded media thumbnail.\n */\n deleteEmbeddedThumbnail = () => {\n Notification.deleteCancelPromise(\n getString('deleteembeddedthumbnail', component),\n getString('deleteembeddedthumbnailwarning', component),\n ).then(async() => {\n if (this.mediaType === 'video') {\n const video = this.root.querySelector('video');\n if (video) {\n video.removeAttribute('poster');\n const preview = this.root.querySelector(Selectors.EMBED.elements.mediaPreviewContainer);\n preview.removeAttribute('data-media-poster');\n }\n }\n\n const deleteCustomThumbnail = this.root.querySelector(Selectors.EMBED.actions.deleteCustomThumbnail);\n deleteCustomThumbnail.remove();\n\n const uploadCustomThumbnail = this.root.querySelector(Selectors.EMBED.actions.uploadCustomThumbnail);\n uploadCustomThumbnail.textContent = await getString('uploadthumbnail', component);\n return;\n }).catch(error => {\n window.console.log(error);\n });\n };\n\n /**\n * Shows the insert thumbnail dialogue.\n */\n showUploadThumbnail = async() => {\n const uploadThumbnailModal = await EmbedModal.create({\n large: true,\n templateContext: {elementid: this.editor.getElement().id},\n });\n const root = uploadThumbnailModal.getRoot()[0];\n\n // Get selected media metadata.\n const mediaData = getEmbeddedMediaDetails(this);\n mediaData.isUpdating = this.isUpdating;\n\n const embedHandler = new EmbedHandler(this);\n embedHandler.loadInsertThumbnailTemplatePromise(\n insertMediaThumbnailTemplateContext(this), // Get template context for creating media thumbnail.\n {root, uploadThumbnailModal}, // Required root elements.\n await embedHandler.getMediaTemplateContext(mediaData) // Get current media data.\n );\n };\n\n /**\n * Only registers event listeners for new loaded elements in embed preview modal.\n */\n registerMediaDetailsEventListeners = async() => {\n // Handle the original size when selected.\n const sizeOriginalEle = this.root.querySelector(Selectors.EMBED.elements.sizeOriginal);\n if (sizeOriginalEle) {\n sizeOriginalEle.addEventListener('change', () => {\n this.sizeChecked('original');\n });\n }\n\n // Handle the custom size when selected.\n const sizeCustomEle = this.root.querySelector(Selectors.EMBED.elements.sizeCustom);\n if (sizeCustomEle) {\n sizeCustomEle.addEventListener('change', () => {\n this.sizeChecked('custom');\n });\n }\n\n const widthEle = this.root.querySelector(Selectors.EMBED.elements.width);\n const heightEle = this.root.querySelector(Selectors.EMBED.elements.height);\n\n // Handle the custom with size when inputted.\n if (widthEle) {\n widthEle.addEventListener('input', () => {\n if (this.mediaType === 'link') {\n // Let's apply the 16:9 aspect ratio if it's a link media type.\n heightEle.value = Math.round(widthEle.value / this.linkMediaAspectRatio);\n } else {\n // Avoid empty value.\n widthEle.value = widthEle.value === \"\" ? 0 : Number(widthEle.value);\n this.autoAdjustSize();\n }\n });\n }\n\n // Handle the custom height size when inputted.\n if (heightEle) {\n heightEle.addEventListener('input', () => {\n if (this.mediaType === 'link') {\n // Let's apply the 16:9 aspect ratio if it's a link media type.\n widthEle.value = Math.round(heightEle.value * this.linkMediaAspectRatio);\n } else {\n // Avoid empty value.\n heightEle.value = heightEle.value === \"\" ? 0 : Number(heightEle.value);\n this.autoAdjustSize(true);\n }\n });\n }\n\n // Handle media preview delete.\n const deleteMedia = this.root.querySelector(Selectors.EMBED.actions.deleteMedia);\n if (deleteMedia) {\n deleteMedia.addEventListener('click', (e) => {\n e.preventDefault();\n this.deleteMedia();\n });\n }\n\n // Show subtitles and captions settings.\n const showSubtitleCaption = this.root.querySelector(Selectors.EMBED.actions.showSubtitleCaption);\n if (showSubtitleCaption) {\n showSubtitleCaption.addEventListener('click', (e) => {\n e.preventDefault();\n hideElements([\n Selectors.EMBED.actions.showSubtitleCaption,\n Selectors.EMBED.actions.cancelMediaDetails,\n Selectors.EMBED.elements.mediaDetailsBody,\n ], this.root);\n showElements([\n Selectors.EMBED.actions.backToMediaDetails,\n Selectors.EMBED.elements.mediaSubtitleCaptionBody,\n ], this.root);\n });\n }\n\n // Back to media preview.\n const backToMediaDetails = this.root.querySelector(Selectors.EMBED.actions.backToMediaDetails);\n if (backToMediaDetails) {\n backToMediaDetails.addEventListener('click', () => {\n hideElements([\n Selectors.EMBED.actions.backToMediaDetails,\n Selectors.EMBED.elements.mediaSubtitleCaptionBody,\n ], this.root);\n showElements([\n Selectors.EMBED.actions.showSubtitleCaption,\n Selectors.EMBED.actions.cancelMediaDetails,\n Selectors.EMBED.elements.mediaDetailsBody,\n ], this.root);\n });\n }\n\n // Handles upload media thumbnail.\n const uploadCustomThumbnail = this.root.querySelector(Selectors.EMBED.actions.uploadCustomThumbnail);\n if (uploadCustomThumbnail) {\n uploadCustomThumbnail.addEventListener('click', () => {\n this.showUploadThumbnail();\n });\n }\n\n // Handles delete media thumbnail.\n const deleteCustomThumbnail = this.root.querySelector(Selectors.EMBED.actions.deleteCustomThumbnail);\n if (deleteCustomThumbnail) {\n deleteCustomThumbnail.addEventListener('click', () => {\n this.deleteEmbeddedThumbnail();\n });\n }\n\n // Handles language track selection.\n const langTracks = this.root.querySelectorAll(Selectors.EMBED.elements.trackLang);\n if (langTracks) {\n langTracks.forEach((dropdown) => {\n const defaultVal = dropdown.getAttribute('data-value');\n if (defaultVal) {\n // ISO 639-1: 2-letter codes (e.g., en for English, fr for French).\n // Most widely used in applications like web development (lang=\"en\" in HTML).\n // Let's check if the value of srclang is language code or language name.\n if (defaultVal.length === 2) {\n const options = dropdown.options;\n for (let i = 0; i < options.length; i++) {\n if (options[i].dataset.languageCode === defaultVal) {\n dropdown.value = options[i].value;\n break;\n }\n }\n } else {\n // It means the value of srclang in track is a full language name like \"English (en)\",\n // which has been like this before this patch.\n dropdown.value = defaultVal;\n }\n }\n });\n }\n };\n}\n"],"names":["EmbedPreview","MediaBase","constructor","data","Selectors","EMBED","type","async","currentModal","setTitle","component","fetchedTitle","this","fetchedMediaLinkTitle","source","originalUrl","root","urlSelector","elements","fromUrl","fileNameSelector","fileNameLabel","setMediaSourceAndPoster","registerMediaDetailsEventListeners","box","querySelector","previewBox","previewArea","document","mediaPreviewContainer","setAttribute","mediaType","newMediaLink","includes","innerHTML","contextId","video","createElement","src","addEventListener","videoHeight","videoWidth","isLandscape","mediaDimensions","width","height","offsetWidth","offsetHeight","value","parseInt","currentWidth","currentHeight","sizeChecked","controls","media","poster","classList","contains","add","load","outerHTML","urlWarning","EmbedHandler","resetUploadForm","audio","mediaDetailsBody","title","setMediaTitle","fileName","isUpdating","mediaTitle","deleteCancelPromise","then","mediaData","catch","error","window","console","log","removeAttribute","actions","deleteCustomThumbnail","remove","uploadCustomThumbnail","textContent","uploadThumbnailModal","EmbedModal","create","large","templateContext","elementid","editor","getElement","id","getRoot","embedHandler","loadInsertThumbnailTemplatePromise","getMediaTemplateContext","sizeOriginalEle","sizeOriginal","sizeCustomEle","sizeCustom","widthEle","heightEle","Math","round","linkMediaAspectRatio","Number","autoAdjustSize","deleteMedia","e","preventDefault","showSubtitleCaption","cancelMediaDetails","backToMediaDetails","mediaSubtitleCaptionBody","showUploadThumbnail","deleteEmbeddedThumbnail","langTracks","querySelectorAll","trackLang","forEach","dropdown","defaultVal","getAttribute","length","options","i","dataset","languageCode"],"mappings":"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"} \ No newline at end of file diff --git a/lib/editor/tiny/plugins/media/amd/src/embed/embedhandler.js b/lib/editor/tiny/plugins/media/amd/src/embed/embedhandler.js index 335008491ec..9f667646f04 100644 --- a/lib/editor/tiny/plugins/media/amd/src/embed/embedhandler.js +++ b/lib/editor/tiny/plugins/media/amd/src/embed/embedhandler.js @@ -513,14 +513,18 @@ export class EmbedHandler { * @returns {object} */ getContextForMediaHTML = (tab, details) => { - const tracks = Array.from(tab.querySelectorAll(Selectors.EMBED.elements.track)).map(track => ({ - track: track.querySelector(Selectors.EMBED.elements.trackSource + ' ' + Selectors.EMBED.elements.url).value, - kind: this.getTrackTypeFromTabPane(track.closest('.tab-pane')), - label: track.querySelector(Selectors.EMBED.elements.trackLabel).value || - track.querySelector(Selectors.EMBED.elements.trackLang).value, - srclang: track.querySelector(Selectors.EMBED.elements.trackLang).value, - defaultTrack: track.querySelector(Selectors.EMBED.elements.trackDefault).checked ? "true" : null - })).filter((track) => !!track.track); + const tracks = Array.from(tab.querySelectorAll(Selectors.EMBED.elements.track)).map(track => { + const langTrack = track.querySelector(Selectors.EMBED.elements.trackLang); + const selectedLangTrack = langTrack.options[langTrack.selectedIndex]; + + return { + track: track.querySelector(Selectors.EMBED.elements.trackSource + ' ' + Selectors.EMBED.elements.url).value, + kind: this.getTrackTypeFromTabPane(track.closest('.tab-pane')), + label: track.querySelector(Selectors.EMBED.elements.trackLabel).value || langTrack.value, + srclang: selectedLangTrack.dataset.languageCode ?? false, + defaultTrack: track.querySelector(Selectors.EMBED.elements.trackDefault).checked ? "true" : null + }; + }).filter((track) => !!track.track); const mediaPreviewContainer = details.querySelector(Selectors.EMBED.elements.mediaPreviewContainer); let sources = mediaPreviewContainer.dataset.originalUrl ?? null; diff --git a/lib/editor/tiny/plugins/media/amd/src/embed/embedhelpers.js b/lib/editor/tiny/plugins/media/amd/src/embed/embedhelpers.js index 7559b64103a..015f0ae6556 100644 --- a/lib/editor/tiny/plugins/media/amd/src/embed/embedhelpers.js +++ b/lib/editor/tiny/plugins/media/amd/src/embed/embedhelpers.js @@ -224,16 +224,16 @@ export const prepareMoodleLang = (editor) => { const moodleLangs = getMoodleLang(editor); const currentLanguage = getCurrentLanguage(editor); - const installed = Object.entries(moodleLangs.installed).map(([lang, code]) => ({ + const installed = Object.entries(moodleLangs.installed).map(([code, lang]) => ({ lang, code, - "default": lang === currentLanguage, + "default": code === currentLanguage, })); - const available = Object.entries(moodleLangs.available).map(([lang, code]) => ({ + const available = Object.entries(moodleLangs.available).map(([code, lang]) => ({ lang, code, - "default": lang === currentLanguage, + "default": code === currentLanguage, })); return { diff --git a/lib/editor/tiny/plugins/media/amd/src/embed/embedpreview.js b/lib/editor/tiny/plugins/media/amd/src/embed/embedpreview.js index 0188972d611..c4ce774c20e 100644 --- a/lib/editor/tiny/plugins/media/amd/src/embed/embedpreview.js +++ b/lib/editor/tiny/plugins/media/amd/src/embed/embedpreview.js @@ -385,7 +385,22 @@ export class EmbedPreview extends MediaBase { langTracks.forEach((dropdown) => { const defaultVal = dropdown.getAttribute('data-value'); if (defaultVal) { - dropdown.value = defaultVal; + // ISO 639-1: 2-letter codes (e.g., en for English, fr for French). + // Most widely used in applications like web development (lang="en" in HTML). + // Let's check if the value of srclang is language code or language name. + if (defaultVal.length === 2) { + const options = dropdown.options; + for (let i = 0; i < options.length; i++) { + if (options[i].dataset.languageCode === defaultVal) { + dropdown.value = options[i].value; + break; + } + } + } else { + // It means the value of srclang in track is a full language name like "English (en)", + // which has been like this before this patch. + dropdown.value = defaultVal; + } } }); } diff --git a/lib/editor/tiny/plugins/media/templates/embed/metadata/captions.mustache b/lib/editor/tiny/plugins/media/templates/embed/metadata/captions.mustache index b3bc304b481..c3e928b4f09 100644 --- a/lib/editor/tiny/plugins/media/templates/embed/metadata/captions.mustache +++ b/lib/editor/tiny/plugins/media/templates/embed/metadata/captions.mustache @@ -61,12 +61,12 @@ @@ -113,12 +113,12 @@ diff --git a/lib/editor/tiny/plugins/media/templates/embed/metadata/chapters.mustache b/lib/editor/tiny/plugins/media/templates/embed/metadata/chapters.mustache index e8b0e40af60..d2bf241c44b 100644 --- a/lib/editor/tiny/plugins/media/templates/embed/metadata/chapters.mustache +++ b/lib/editor/tiny/plugins/media/templates/embed/metadata/chapters.mustache @@ -61,12 +61,12 @@ @@ -113,12 +113,12 @@ diff --git a/lib/editor/tiny/plugins/media/templates/embed/metadata/descriptions.mustache b/lib/editor/tiny/plugins/media/templates/embed/metadata/descriptions.mustache index 670d4022dbd..db16c405361 100644 --- a/lib/editor/tiny/plugins/media/templates/embed/metadata/descriptions.mustache +++ b/lib/editor/tiny/plugins/media/templates/embed/metadata/descriptions.mustache @@ -61,12 +61,12 @@ @@ -113,12 +113,12 @@ diff --git a/lib/editor/tiny/plugins/media/templates/embed/metadata/metadata.mustache b/lib/editor/tiny/plugins/media/templates/embed/metadata/metadata.mustache index af607a2f1bd..07f70401872 100644 --- a/lib/editor/tiny/plugins/media/templates/embed/metadata/metadata.mustache +++ b/lib/editor/tiny/plugins/media/templates/embed/metadata/metadata.mustache @@ -61,12 +61,12 @@ @@ -113,12 +113,12 @@ diff --git a/lib/editor/tiny/plugins/media/templates/embed/metadata/subtitles.mustache b/lib/editor/tiny/plugins/media/templates/embed/metadata/subtitles.mustache index e92c522594b..a9039fef4bf 100644 --- a/lib/editor/tiny/plugins/media/templates/embed/metadata/subtitles.mustache +++ b/lib/editor/tiny/plugins/media/templates/embed/metadata/subtitles.mustache @@ -61,12 +61,12 @@ @@ -113,12 +113,12 @@ diff --git a/lib/editor/tiny/plugins/media/tests/behat/media.feature b/lib/editor/tiny/plugins/media/tests/behat/media.feature index c3d27a21f3a..bf05ccd2097 100644 --- a/lib/editor/tiny/plugins/media/tests/behat/media.feature +++ b/lib/editor/tiny/plugins/media/tests/behat/media.feature @@ -46,13 +46,13 @@ Feature: Use the TinyMCE editor to upload a media file And I click on "Subtitles and captions" "link" in the "Media details" "dialogue" And I click on "Browse repositories..." "button" in the "Media details" "dialogue" And I upload "/lib/editor/tiny/tests/behat/fixtures/" to the file picker for TinyMCE - And I set the field "Language" in the "Media details" "dialogue" to "" + And I set the field "Language" in the "Media details" "dialogue" to "" And I set the field "Label" in the "Media details" "dialogue" to "" And I click on "Save" "button" in the "Media details" "dialogue" And I switch to the "Description" TinyMCE editor iframe And "//*[contains(@data-id, 'id_description_editor')]//[@title='' and @autoplay='autoplay' and @loop='loop' and @muted='true' and @controls='controls']" "xpath_element" should exist And "//*[contains(@data-id, 'id_description_editor')]////source[contains(@src, '')]" "xpath_element" should exist - And "//*[contains(@data-id, 'id_description_editor')]////track[contains(@src, '') and @kind='subtitles' and contains(@srclang, '') and @label='']" "xpath_element" should exist + And "//*[contains(@data-id, 'id_description_editor')]////track[contains(@src, '') and @kind='subtitles' and contains(@srclang, '') and @label='']" "xpath_element" should exist And I switch to the main frame And I select the "video" element in position "1" of the "Description" TinyMCE editor And I click on the "Multimedia" button for the "Description" TinyMCE editor @@ -65,12 +65,12 @@ Feature: Use the TinyMCE editor to upload a media file And And I click on "Subtitles and captions" "link" in the "Media details" "dialogue" And the field "Subtitle track URL" in the "Media details" "dialogue" does not match value "" - And the field "Language" in the "Media details" "dialogue" matches value "" + And the field "Language" in the "Media details" "dialogue" matches value "" And the field "Label" in the "Media details" "dialogue" matches value "" Examples: | mediatype | fixturefile | fixturetitle | newfixturetitle | subtitlefile | subtitletitle | subtitlelangcode | subtitlelang | thumbnailaction | originalsizeverify | customsizeverify1 | customsizeverify2 | customsizeverify3 | customsizestep | customsizeaction | - | video | moodle-logo.mp4 | moodle-logo | Moodle LMS Logo | subtitle-sample.vtt | Subtitle sample for video | en | English | should exist | the field "Original size" in the "Media details" "dialogue" matches value "1" | the field "Custom size" in the "Media details" "dialogue" matches value "0" | the field "Custom size" in the "Media details" "dialogue" matches value "1" | the field "Width" in the "Media details" "dialogue" matches value "300" | I click on "Custom size" "radio" in the "Media details" "dialogue" | I set the field "Width" in the "Media details" "dialogue" to "300" | + | video | moodle-logo.mp4 | moodle-logo | Moodle LMS Logo | subtitle-sample.vtt | Subtitle sample for video | he | Hebrew | should exist | the field "Original size" in the "Media details" "dialogue" matches value "1" | the field "Custom size" in the "Media details" "dialogue" matches value "0" | the field "Custom size" in the "Media details" "dialogue" matches value "1" | the field "Width" in the "Media details" "dialogue" matches value "300" | I click on "Custom size" "radio" in the "Media details" "dialogue" | I set the field "Width" in the "Media details" "dialogue" to "300" | | audio | audio-sample.mp3 | audio-sample | Sample Audio File | subtitle-sample.vtt | Subtitle sample for audio | fr | French | should not exist | "Original size" "field" should not exist in the "Media details" "dialogue" | "Custom size" "field" should not exist in the "Media details" "dialogue" | "Custom size" "field" should not exist in the "Media details" "dialogue" | "Width" "field" should not exist in the "Media details" "dialogue" | "Original size" "field" should not exist in the "Media details" "dialogue" | "Custom size" "field" should not exist in the "Media details" "dialogue" | @_file_upload