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 42c70cbdba1..d6469ae0558 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"],(function(_exports,_selectors,_embedinsert,_helpers,ModalEvents,_utils,_embedhelpers){var obj;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 _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=(obj=_selectors)&&obj.__esModule?obj:{default:obj},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);_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="EMBED",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,"loadMediaDetails",(async(embedPreview,templateContext)=>{Promise.all([(0,_helpers.body)(templateContext,this.root),(0,_helpers.footer)(templateContext,this.root)]).then((()=>{if((0,_helpers.hideElements)(_selectors.default.EMBED.elements.bodyTemplate,this.root),this.mediaData){this.currentModal.uploadThumbnailModal.destroy();const currentModal=this.currentModal.insertMediaModal;this.currentModal=currentModal.insertMediaModal}embedPreview.init()})).catch((error=>{this.mediaData||(0,_helpers.stopMediaLoading)(this.root,"EMBED"),window.console.log(error)}))})),_defineProperty(this,"resetUploadForm",(()=>{this.mediaType=null,this.loadTemplatePromise((0,_embedhelpers.insertMediaTemplateContext)(this))})),_defineProperty(this,"getMediumProperties",(()=>{const boolAttr=(elem,attr)=>elem.hasAttribute(attr)&&(elem.getAttribute(attr)||""===elem.getAttribute(attr)),medium=this.selectedMedia;if(!medium)return null;if("link"===this.mediaType){const urlParams=(0,_helpers.convertStringUrlToObject)(medium.href),mediaData={type:this.mediaType,title:medium.textContent.trim()};for(const param in urlParams){let prop=param;"mute"===param&&(prop="muted");const isTrue="true"===urlParams[param]||"1"===urlParams[param];mediaData[prop]=isTrue}return mediaData}{const tracks={subtitles:[],captions:[],descriptions:[],chapters:[],metadata:[]},sources=[];medium.querySelectorAll("track").forEach((track=>{tracks[track.getAttribute("kind")].push({src:track.getAttribute("src"),srclang:track.getAttribute("srclang"),label:track.getAttribute("label"),defaultTrack:boolAttr(track,"default")})})),medium.querySelectorAll("source").forEach((source=>{sources.push(source.src)}));const title=medium.getAttribute("title");return{type:this.mediaType,sources:sources,poster:medium.getAttribute("poster"),title:!!title&&title.trim(),width:medium.getAttribute("width"),height:medium.getAttribute("height"),autoplay:boolAttr(medium,"autoplay"),loop:boolAttr(medium,"loop"),muted:boolAttr(medium,"muted"),controls:boolAttr(medium,"controls"),tracks:tracks}}})),_defineProperty(this,"getCurrentEmbedData",(()=>{const properties=this.getMediumProperties();if(!properties)return{};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=Object.assign({},_this.getCurrentEmbedData())),_this.isUpdating=0!==Object.keys(data).length,await _this.getTemplateContext(data)})),_defineProperty(this,"loadMediaPreview",(url=>{new _embedinsert.EmbedInsert(this).loadMediaPreview(url)})),_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)&&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,"registerEventListeners",(async modal=>{await modal.getBody();const $root=modal.getRoot(),root=$root[0];this.canShowFilePickerTrack&&root.addEventListener("click",this.clickHandler.bind(this)),root.addEventListener("input",(e=>{const urlEle=e.target.closest(_selectors.default.EMBED.elements.fromUrl);urlEle&&this.toggleUrlButton(urlEle)})),$root.on(ModalEvents.hidden,(()=>{this.currentModal.destroy()})),$root.on(ModalEvents.shown,(()=>{this.root.querySelectorAll(_selectors.default.EMBED.elements.trackLang).forEach((dropdown=>{const defaultVal=dropdown.getAttribute("data-value");defaultVal&&(dropdown.value=defaultVal)}))}))})),(0,_helpers.setPropertiesFromData)(this,_data)}urlChanged(){(0,_helpers.hideElements)(_selectors.default.EMBED.elements.urlWarning,this.root);const url=this.root.querySelector(_selectors.default.EMBED.elements.fromUrl).value;url&&url!==this.currentUrl&&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.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){const url=input.value;this.root.querySelector(_selectors.default.EMBED.actions.addUrl).disabled=!(""!==url&&(0,_helpers.isValidUrl)(url))}}})); +define("tiny_media/embed/embedhandler",["exports","../selectors","./embedinsert","../helpers","core/modal_events","editor_tiny/utils","./embedhelpers","core/templates"],(function(_exports,_selectors,_embedinsert,_helpers,ModalEvents,_utils,_embedhelpers,_templates){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="EMBED",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,"loadMediaDetails",(async(embedPreview,templateContext)=>{Promise.all([(0,_helpers.body)(templateContext,this.root),(0,_helpers.footer)(templateContext,this.root)]).then((()=>{if((0,_helpers.hideElements)(_selectors.default.EMBED.elements.bodyTemplate,this.root),this.mediaData){this.currentModal.uploadThumbnailModal.destroy();const currentModal=this.currentModal.insertMediaModal;this.currentModal=currentModal.insertMediaModal}embedPreview.init()})).catch((error=>{this.mediaData||(0,_helpers.stopMediaLoading)(this.root,"EMBED"),window.console.log(error)}))})),_defineProperty(this,"resetUploadForm",(()=>{this.mediaType=null,this.loadTemplatePromise((0,_embedhelpers.insertMediaTemplateContext)(this))})),_defineProperty(this,"getMediumProperties",(()=>{const boolAttr=(elem,attr)=>elem.hasAttribute(attr)&&(elem.getAttribute(attr)||""===elem.getAttribute(attr)),medium=this.selectedMedia;if(!medium)return null;if("link"===this.mediaType){const urlParams=(0,_helpers.convertStringUrlToObject)(medium.href),mediaData={type:this.mediaType,title:medium.textContent.trim()};for(const param in urlParams){let prop=param;"mute"===param&&(prop="muted");const isTrue="true"===urlParams[param]||"1"===urlParams[param];mediaData[prop]=isTrue}return mediaData}{const tracks={subtitles:[],captions:[],descriptions:[],chapters:[],metadata:[]},sources=[];medium.querySelectorAll("track").forEach((track=>{tracks[track.getAttribute("kind")].push({src:track.getAttribute("src"),srclang:track.getAttribute("srclang"),label:track.getAttribute("label"),defaultTrack:boolAttr(track,"default")})})),medium.querySelectorAll("source").forEach((source=>{sources.push(source.src)}));const title=medium.getAttribute("title");return{type:this.mediaType,sources:sources,poster:medium.getAttribute("poster"),title:!!title&&title.trim(),width:medium.getAttribute("width"),height:medium.getAttribute("height"),autoplay:boolAttr(medium,"autoplay"),loop:boolAttr(medium,"loop"),muted:boolAttr(medium,"muted"),controls:boolAttr(medium,"controls"),tracks:tracks}}})),_defineProperty(this,"getCurrentEmbedData",(()=>{const properties=this.getMediumProperties();if(!properties)return{};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=Object.assign({},_this.getCurrentEmbedData())),_this.isUpdating=0!==Object.keys(data).length,await _this.getTemplateContext(data)})),_defineProperty(this,"loadMediaPreview",(url=>{new _embedinsert.EmbedInsert(this).loadMediaPreview(url)})),_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)&&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=>{let mediumType=this.root.querySelector(_selectors.default.EMBED.elements.previewClass).nodeName.toLowerCase();mediumType="iframe"===mediumType?"link":mediumType;const tabContent=form.querySelector(".tab-content");return this["getMediaHTML"+mediumType[0].toUpperCase()+mediumType.substr(1)](tabContent)})),_defineProperty(this,"getMediaHTMLLink",(()=>{var _details$querySelecto;const details=document.querySelector(_selectors.default.EMBED.elements.mediaDetailsBody),url=null!==(_details$querySelecto=details.querySelector(_selectors.default.EMBED.elements.preview).src)&&void 0!==_details$querySelecto?_details$querySelecto:null,urlParamString=(0,_helpers.createUrlParams)({controls:details.querySelector(_selectors.default.EMBED.elements.mediaControl).checked?1:0,autoplay:details.querySelector(_selectors.default.EMBED.elements.mediaAutoplay).checked?1:0,mute:details.querySelector(_selectors.default.EMBED.elements.mediaMute).checked?1:0}),name=details.querySelector(_selectors.default.EMBED.elements.title).value||!1,context={url:(0,_embedhelpers.getLinkBasedUrl)(url)+urlParamString,name:!!name&&name.trim()};return context.url?_templates.default.renderForPromise("tiny_media/embed/embed_media_link",context):""})),_defineProperty(this,"getMediaHTMLVideo",(tab=>{const details=document.querySelector(_selectors.default.EMBED.elements.mediaDetailsBody),context=this.getContextForMediaHTML(tab,details);return context.width=details.querySelector(_selectors.default.EMBED.elements.width).value||!1,context.height=details.querySelector(_selectors.default.EMBED.elements.height).value||!1,context.poster=details.querySelector(_selectors.default.EMBED.elements.videoTag).poster||!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 _details$querySelecto2;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)),sources=null!==(_details$querySelecto2=details.querySelector(_selectors.default.EMBED.elements.preview).src)&&void 0!==_details$querySelecto2?_details$querySelecto2:null,title=details.querySelector(_selectors.default.EMBED.elements.title).value;return{sources:sources,description:tab.querySelector(_selectors.default.EMBED.elements.url).value||!1,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()}})),_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 modal=>{await modal.getBody();const $root=modal.getRoot(),root=$root[0];this.canShowFilePickerTrack&&root.addEventListener("click",this.clickHandler.bind(this)),root.addEventListener("input",(e=>{const urlEle=e.target.closest(_selectors.default.EMBED.elements.fromUrl);urlEle&&this.toggleUrlButton(urlEle)})),$root.on(ModalEvents.hidden,(()=>{this.currentModal.destroy()})),$root.on(ModalEvents.shown,(()=>{this.root.querySelectorAll(_selectors.default.EMBED.elements.trackLang).forEach((dropdown=>{const defaultVal=dropdown.getAttribute("data-value");defaultVal&&(dropdown.value=defaultVal)}))})),$root.on(ModalEvents.save,this.handleDialogueSubmission.bind(this))})),(0,_helpers.setPropertiesFromData)(this,_data)}urlChanged(){(0,_helpers.hideElements)(_selectors.default.EMBED.elements.urlWarning,this.root);const url=this.root.querySelector(_selectors.default.EMBED.elements.fromUrl).value;url&&url!==this.currentUrl&&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.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){const url=input.value;this.root.querySelector(_selectors.default.EMBED.actions.addUrl).disabled=!(""!==url&&(0,_helpers.isValidUrl)(url))}}})); //# 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 1cbbed8e8ad..27594c26495 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 hideElements,\n isValidUrl,\n convertStringUrlToObject,\n stopMediaLoading,\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} from \"./embedhelpers\";\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 = 'EMBED';\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 * 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 // Hide the body template when preparing the media preview.\n hideElements(Selectors.EMBED.elements.bodyTemplate, this.root);\n\n if (this.mediaData) { // It came from mediaThumbnail and we should kill uploadThumbnailModal modal.\n this.currentModal.uploadThumbnailModal.destroy();\n const currentModal = this.currentModal.insertMediaModal;\n this.currentModal = currentModal.insertMediaModal;\n }\n embedPreview.init();\n return;\n })\n .catch(error => {\n if (!this.mediaData) { // It came from mediaThumbnail and we did not init startMediaLoading from there.\n stopMediaLoading(this.root, 'EMBED');\n }\n window.console.log(error);\n });\n };\n\n /**\n * Reset the media insert modal form.\n */\n resetUploadForm = () => {\n this.mediaType = null; // Set to null to be set again.\n this.loadTemplatePromise(insertMediaTemplateContext(this));\n };\n\n /**\n * Get selected media data.\n *\n * @returns {null|object}\n */\n getMediumProperties = () => {\n const boolAttr = (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\n const medium = this.selectedMedia;\n if (!medium) {\n return null;\n }\n\n const isLink = (this.mediaType === 'link');\n if (isLink) {\n const urlParams = convertStringUrlToObject(medium.href);\n const mediaData = {\n type: this.mediaType,\n title: medium.textContent.trim(),\n };\n\n for (const param in urlParams) {\n let prop = param;\n if (param === 'mute') {\n prop = 'muted';\n }\n const isTrue = (urlParams[param] === 'true') || (urlParams[param] === '1');\n mediaData[prop] = isTrue;\n }\n return mediaData;\n } else {\n const tracks = {\n subtitles: [],\n captions: [],\n descriptions: [],\n chapters: [],\n metadata: []\n };\n const sources = [];\n\n medium.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: boolAttr(track, 'default')\n });\n });\n\n medium.querySelectorAll('source').forEach((source) => {\n sources.push(source.src);\n });\n const title = medium.getAttribute('title');\n\n return {\n type: this.mediaType,\n sources,\n poster: medium.getAttribute('poster'),\n title: title ? title.trim() : false,\n width: medium.getAttribute('width'),\n height: medium.getAttribute('height'),\n autoplay: boolAttr(medium, 'autoplay'),\n loop: boolAttr(medium, 'loop'),\n muted: boolAttr(medium, 'muted'),\n controls: boolAttr(medium, 'controls'),\n tracks,\n };\n }\n };\n\n /**\n * Get selected media data.\n *\n * @returns {object}\n */\n getCurrentEmbedData = () => {\n const properties = this.getMediumProperties();\n if (!properties) {\n return {};\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 }\n this.isUpdating = Object.keys(data).length !== 0;\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 hideElements(Selectors.EMBED.elements.urlWarning, this.root);\n const url = this.root.querySelector(Selectors.EMBED.elements.fromUrl).value;\n if (url && url !== this.currentUrl) {\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 this.loadMediaPreview(params.url);\n }\n }\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 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 const addUrlEle = e.target.closest(Selectors.EMBED.actions.addUrl);\n if (addUrlEle) {\n this.urlChanged();\n }\n\n const addComponentTrackAction = element.closest(Selectors.EMBED.elements.track + ' .addcomponent');\n if (addComponentTrackAction) {\n e.preventDefault();\n this.addTrackComponent(element);\n }\n\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 */\n toggleUrlButton(input) {\n const url = input.value;\n const addUrl = this.root.querySelector(Selectors.EMBED.actions.addUrl);\n addUrl.disabled = !(url !== \"\" && isValidUrl(url));\n }\n\n registerEventListeners = async(modal) => {\n await modal.getBody();\n const $root = modal.getRoot();\n const root = $root[0];\n if (this.canShowFilePickerTrack) {\n root.addEventListener('click', this.clickHandler.bind(this));\n }\n\n root.addEventListener('input', (e) => {\n const urlEle = e.target.closest(Selectors.EMBED.elements.fromUrl);\n if (urlEle) {\n this.toggleUrlButton(urlEle);\n }\n });\n\n $root.on(ModalEvents.hidden, () => {\n this.currentModal.destroy();\n });\n\n $root.on(ModalEvents.shown, () => {\n this.root.querySelectorAll(Selectors.EMBED.elements.trackLang).forEach((dropdown) => {\n const defaultVal = dropdown.getAttribute('data-value');\n if (defaultVal) {\n dropdown.value = defaultVal;\n }\n });\n });\n };\n}\n"],"names":["constructor","data","templateContext","elementid","this","editor","id","bodyTemplate","Selectors","EMBED","template","body","insertMediaBody","footerTemplate","footer","insertMediaFooter","selector","Promise","all","root","then","EmbedInsert","init","catch","error","window","console","log","async","embedPreview","elements","mediaData","currentModal","uploadThumbnailModal","destroy","insertMediaModal","mediaType","loadTemplatePromise","boolAttr","elem","attr","hasAttribute","getAttribute","medium","selectedMedia","urlParams","href","type","title","textContent","trim","param","prop","isTrue","tracks","subtitles","captions","descriptions","chapters","metadata","sources","querySelectorAll","forEach","track","push","src","srclang","label","defaultTrack","source","poster","width","height","autoplay","loop","muted","controls","properties","getMediumProperties","processedProperties","media","link","helpStrings","languages","helpIcons","Array","from","Object","entries","getHelpStrings","_ref","key","text","toLowerCase","assign","getElement","showFilePickerTrack","canShowFilePickerTrack","langsInstalled","installed","langsAvailable","available","isUpdating","_this","getCurrentEmbedData","keys","length","getTemplateContext","url","loadMediaPreview","element","closest","posterSource","trackSource","tabPane","e","target","actions","mediaBrowser","preventDefault","fpType","getFilePickerTypeFromElement","params","trackFilePickerCallback","addUrl","urlChanged","addTrackComponent","removeTrackComponent","trackDefaultAction","trackDefault","checked","getKind","el","getTrackTypeFromTabPane","parentElement","select","modal","getBody","$root","getRoot","addEventListener","clickHandler","bind","urlEle","fromUrl","toggleUrlButton","on","ModalEvents","hidden","shown","trackLang","dropdown","defaultVal","value","urlWarning","querySelector","currentUrl","subtitleLang","file","split","slice","langObj","trackLabel","lang","code","trackElement","clone","cloneNode","classList","remove","add","parentNode","insertBefore","nextSibling","input","disabled"],"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 hideElements,\n isValidUrl,\n convertStringUrlToObject,\n stopMediaLoading,\n createUrlParams,\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 getLinkBasedUrl,\n} from \"./embedhelpers\";\nimport Templates from 'core/templates';\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 = 'EMBED';\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 * 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 // Hide the body template when preparing the media preview.\n hideElements(Selectors.EMBED.elements.bodyTemplate, this.root);\n\n if (this.mediaData) { // It came from mediaThumbnail and we should kill uploadThumbnailModal modal.\n this.currentModal.uploadThumbnailModal.destroy();\n const currentModal = this.currentModal.insertMediaModal;\n this.currentModal = currentModal.insertMediaModal;\n }\n embedPreview.init();\n return;\n })\n .catch(error => {\n if (!this.mediaData) { // It came from mediaThumbnail and we did not init startMediaLoading from there.\n stopMediaLoading(this.root, 'EMBED');\n }\n window.console.log(error);\n });\n };\n\n /**\n * Reset the media insert modal form.\n */\n resetUploadForm = () => {\n this.mediaType = null; // Set to null to be set again.\n this.loadTemplatePromise(insertMediaTemplateContext(this));\n };\n\n /**\n * Get selected media data.\n *\n * @returns {null|object}\n */\n getMediumProperties = () => {\n const boolAttr = (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\n const medium = this.selectedMedia;\n if (!medium) {\n return null;\n }\n\n const isLink = (this.mediaType === 'link');\n if (isLink) {\n const urlParams = convertStringUrlToObject(medium.href);\n const mediaData = {\n type: this.mediaType,\n title: medium.textContent.trim(),\n };\n\n for (const param in urlParams) {\n let prop = param;\n if (param === 'mute') {\n prop = 'muted';\n }\n const isTrue = (urlParams[param] === 'true') || (urlParams[param] === '1');\n mediaData[prop] = isTrue;\n }\n return mediaData;\n } else {\n const tracks = {\n subtitles: [],\n captions: [],\n descriptions: [],\n chapters: [],\n metadata: []\n };\n const sources = [];\n\n medium.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: boolAttr(track, 'default')\n });\n });\n\n medium.querySelectorAll('source').forEach((source) => {\n sources.push(source.src);\n });\n const title = medium.getAttribute('title');\n\n return {\n type: this.mediaType,\n sources,\n poster: medium.getAttribute('poster'),\n title: title ? title.trim() : false,\n width: medium.getAttribute('width'),\n height: medium.getAttribute('height'),\n autoplay: boolAttr(medium, 'autoplay'),\n loop: boolAttr(medium, 'loop'),\n muted: boolAttr(medium, 'muted'),\n controls: boolAttr(medium, 'controls'),\n tracks,\n };\n }\n };\n\n /**\n * Get selected media data.\n *\n * @returns {object}\n */\n getCurrentEmbedData = () => {\n const properties = this.getMediumProperties();\n if (!properties) {\n return {};\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 }\n this.isUpdating = Object.keys(data).length !== 0;\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 hideElements(Selectors.EMBED.elements.urlWarning, this.root);\n const url = this.root.querySelector(Selectors.EMBED.elements.fromUrl).value;\n if (url && url !== this.currentUrl) {\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 this.loadMediaPreview(params.url);\n }\n }\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 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 const addUrlEle = e.target.closest(Selectors.EMBED.actions.addUrl);\n if (addUrlEle) {\n this.urlChanged();\n }\n\n const addComponentTrackAction = element.closest(Selectors.EMBED.elements.track + ' .addcomponent');\n if (addComponentTrackAction) {\n e.preventDefault();\n this.addTrackComponent(element);\n }\n\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 */\n toggleUrlButton(input) {\n const url = input.value;\n const addUrl = this.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 let mediumType = this.root.querySelector(Selectors.EMBED.elements.previewClass).nodeName.toLowerCase();\n mediumType = (mediumType === 'iframe') ? 'link' : mediumType;\n const tabContent = form.querySelector('.tab-content');\n const callback = 'getMediaHTML' + mediumType[0].toUpperCase() + mediumType.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 details = document.querySelector(Selectors.EMBED.elements.mediaDetailsBody);\n const url = details.querySelector(Selectors.EMBED.elements.preview).src ?? null;\n const urlParamString = createUrlParams({\n controls: details.querySelector(Selectors.EMBED.elements.mediaControl).checked ? 1 : 0,\n autoplay: details.querySelector(Selectors.EMBED.elements.mediaAutoplay).checked ? 1 : 0,\n mute: details.querySelector(Selectors.EMBED.elements.mediaMute).checked ? 1 : 0,\n });\n const name = details.querySelector(Selectors.EMBED.elements.title).value || false;\n const context = {\n url: getLinkBasedUrl(url) + urlParamString,\n name: name ? name.trim() : 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 context.poster = details.querySelector(Selectors.EMBED.elements.videoTag).poster || 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 sources = details.querySelector(Selectors.EMBED.elements.preview).src ?? null;\n const title = details.querySelector(Selectors.EMBED.elements.title).value;\n\n return {\n sources,\n description: tab.querySelector(Selectors.EMBED.elements.url).value || false,\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\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 registerEventListeners = async(modal) => {\n await modal.getBody();\n const $root = modal.getRoot();\n const root = $root[0];\n if (this.canShowFilePickerTrack) {\n root.addEventListener('click', this.clickHandler.bind(this));\n }\n\n root.addEventListener('input', (e) => {\n const urlEle = e.target.closest(Selectors.EMBED.elements.fromUrl);\n if (urlEle) {\n this.toggleUrlButton(urlEle);\n }\n });\n\n $root.on(ModalEvents.hidden, () => {\n this.currentModal.destroy();\n });\n\n $root.on(ModalEvents.shown, () => {\n this.root.querySelectorAll(Selectors.EMBED.elements.trackLang).forEach((dropdown) => {\n const defaultVal = dropdown.getAttribute('data-value');\n if (defaultVal) {\n dropdown.value = defaultVal;\n }\n });\n });\n\n $root.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","Promise","all","root","then","EmbedInsert","init","catch","error","window","console","log","async","embedPreview","elements","mediaData","currentModal","uploadThumbnailModal","destroy","insertMediaModal","mediaType","loadTemplatePromise","boolAttr","elem","attr","hasAttribute","getAttribute","medium","selectedMedia","urlParams","href","type","title","textContent","trim","param","prop","isTrue","tracks","subtitles","captions","descriptions","chapters","metadata","sources","querySelectorAll","forEach","track","push","src","srclang","label","defaultTrack","source","poster","width","height","autoplay","loop","muted","controls","properties","getMediumProperties","processedProperties","media","link","helpStrings","languages","helpIcons","Array","from","Object","entries","getHelpStrings","_ref","key","text","toLowerCase","assign","getElement","showFilePickerTrack","canShowFilePickerTrack","langsInstalled","installed","langsAvailable","available","isUpdating","_this","getCurrentEmbedData","keys","length","getTemplateContext","url","loadMediaPreview","element","closest","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","mediumType","querySelector","previewClass","nodeName","tabContent","toUpperCase","substr","details","document","mediaDetailsBody","preview","urlParamString","mediaControl","mediaAutoplay","mute","mediaMute","name","value","context","Templates","renderForPromise","tab","getContextForMediaHTML","videoTag","map","kind","trackLabel","trackLang","filter","description","showControls","mediaLoop","event","modal","html","getMediaHTML","getRoot","outerHTML","insertContent","getBody","$root","addEventListener","clickHandler","bind","urlEle","fromUrl","toggleUrlButton","on","ModalEvents","hidden","shown","dropdown","defaultVal","save","handleDialogueSubmission","urlWarning","currentUrl","subtitleLang","file","split","slice","langObj","lang","code","trackElement","clone","cloneNode","classList","remove","add","parentNode","insertBefore","nextSibling","input","disabled"],"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 ef494c5fbf9..6ede00ef836 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","../helpers","c * @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.isUrlFromKnownMediaSites=_exports.insertMediaTemplateContext=_exports.getSelectedMediaElement=_exports.getMoodleLangObj=_exports.getHelpStrings=_exports.getEmbeddedMediaDetails=_exports.formatMediaUrl=void 0,_selectors=(obj=_selectors)&&obj.__esModule?obj:{default:obj};_exports.insertMediaTemplateContext=props=>({mediaType:props.mediaType,showDropzone:props.canShowDropZone,showFilePicker:props.canShowFilePicker});_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):"a"===mediaElm.nodeName.toLowerCase()?(mediaType="link",selectedMedia=mediaElm):mediaElm.querySelector("video")?(mediaType="video",selectedMedia=mediaElm.querySelector("video")):mediaElm.querySelector("audio")&&(mediaType="audio",selectedMedia=mediaElm.querySelector("audio")):(mediaType=null,selectedMedia=null),[mediaType,selectedMedia]};_exports.formatMediaUrl=url=>{const params=(0,_helpers.convertStringUrlToObject)(url);if(url.includes(_selectors.default.EMBED.mediaSites.youtube)){let fetchedUrl=null,fetchedUrlValue=null;for(const k in params)if(url.includes(k)){fetchedUrl=k,fetchedUrlValue=params[k],delete params[k];break}url=(url=fetchedUrl.replace("watch?v","embed/"))+fetchedUrlValue+"?"+(0,_helpers.createUrlParams)(params)}return url};_exports.isUrlFromKnownMediaSites=url=>{let state=!1;const sites=_selectors.default.EMBED.mediaSites;for(const site in sites)if(url.includes(sites[site])){state=!0;break}return state};_exports.mediaDetailsTemplateContext=async props=>{const context={bodyTemplate:_selectors.default.EMBED.template.body.mediaDetailsBody,footerTemplate:_selectors.default.EMBED.template.footer.mediaDetailsFooter,isVideo:"video"===props.mediaType,isAudio:"audio"===props.mediaType,isLink:"link"===props.mediaType,isUpdating:props.isUpdating};return props.mediaData?{...context,...props.mediaData}:{...context,...await props.mediaTemplateContext}};_exports.getHelpStrings=async()=>{const[customsize]=await(0,_str.getStrings)(["customsize_help"].map((key=>({key:key,component:_common.component}))));return{customsize:customsize}};_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=>{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:querySelector(_selectors.default.EMBED.elements.videoTag).getAttribute("poster"),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}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.prepareMoodleLang=_exports.mediaDetailsTemplateContext=_exports.isUrlFromKnownMediaSites=_exports.insertMediaTemplateContext=_exports.getSelectedMediaElement=_exports.getMoodleLangObj=_exports.getLinkBasedUrl=_exports.getHelpStrings=_exports.getEmbeddedMediaDetails=_exports.formatMediaUrl=void 0,_selectors=(obj=_selectors)&&obj.__esModule?obj:{default:obj};_exports.insertMediaTemplateContext=props=>({mediaType:props.mediaType,showDropzone:props.canShowDropZone,showFilePicker:props.canShowFilePicker});_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):"a"===mediaElm.nodeName.toLowerCase()?(mediaType="link",selectedMedia=mediaElm):mediaElm.querySelector("video")?(mediaType="video",selectedMedia=mediaElm.querySelector("video")):mediaElm.querySelector("audio")&&(mediaType="audio",selectedMedia=mediaElm.querySelector("audio")):(mediaType=null,selectedMedia=null),[mediaType,selectedMedia]};_exports.formatMediaUrl=url=>{const params=(0,_helpers.convertStringUrlToObject)(url);if(url.includes(_selectors.default.EMBED.mediaSites.youtube)){let fetchedUrl=null,fetchedUrlValue=null;for(const k in params)if(url.includes(k)){fetchedUrl=k,fetchedUrlValue=params[k],delete params[k];break}url=(url=fetchedUrl.replace("watch?v","embed/"))+fetchedUrlValue+"?"+(0,_helpers.createUrlParams)(params)}return url};_exports.isUrlFromKnownMediaSites=url=>{let state=!1;const sites=_selectors.default.EMBED.mediaSites;for(const site in sites)if(url.includes(sites[site])){state=!0;break}return state};_exports.mediaDetailsTemplateContext=async props=>{const context={bodyTemplate:_selectors.default.EMBED.template.body.mediaDetailsBody,footerTemplate:_selectors.default.EMBED.template.footer.mediaDetailsFooter,isVideo:"video"===props.mediaType,isAudio:"audio"===props.mediaType,isLink:"link"===props.mediaType,isUpdating:props.isUpdating};return props.mediaData?{...context,...props.mediaData}:{...context,...await props.mediaTemplateContext}};_exports.getHelpStrings=async()=>{const[customsize]=await(0,_str.getStrings)(["customsize_help"].map((key=>({key:key,component:_common.component}))));return{customsize:customsize}};_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=>{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:querySelector(_selectors.default.EMBED.elements.videoTag).getAttribute("poster"),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.getLinkBasedUrl=url=>{if(url.includes(_selectors.default.EMBED.mediaSites.youtube)&&url.includes("embed/")){const urlParams=url.split("embed/");let id=null;id=urlParams[1].includes("?")?urlParams[1].split("?")[0]:urlParams[1],url="".concat(urlParams[0],"watch?v=").concat(id,"&")}return url}})); //# 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 fd14580f0b7..a1e6f5a2788 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 {\n convertStringUrlToObject,\n createUrlParams,\n} from '../helpers';\nimport {getStrings} from 'core/str';\nimport {component} from \"../common\";\nimport {\n getCurrentLanguage,\n getMoodleLang\n} from 'editor_tiny/options';\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 };\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.nodeName.toLowerCase() === 'a') {\n mediaType = 'link';\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 }\n\n return [mediaType, selectedMedia];\n};\n\n/**\n * Format url when inserting media link to be previewed.\n *\n * @param {string} url\n * @returns {string}\n */\nexport const formatMediaUrl = (url) => {\n // Convert the string url into url param object.\n const params = convertStringUrlToObject(url);\n\n // Format the url for youtube links.\n if (url.includes(Selectors.EMBED.mediaSites.youtube)) {\n let fetchedUrl = null;\n let fetchedUrlValue = null;\n for (const k in params) {\n if (url.includes(k)) {\n fetchedUrl = k;\n fetchedUrlValue = params[k];\n delete params[k];\n break;\n }\n }\n url = fetchedUrl.replace('watch?v', 'embed/');\n url = url + fetchedUrlValue + '?' + createUrlParams(params);\n }\n return url;\n};\n\n/**\n * Check if the url is from a known media site.\n *\n * @param {string} url\n * @returns {boolean}\n */\nexport const isUrlFromKnownMediaSites = (url) => {\n let state = false;\n const sites = Selectors.EMBED.mediaSites;\n for (const site in sites) {\n if (url.includes(sites[site])) {\n state = true;\n break;\n }\n }\n return state;\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 isVideo: (props.mediaType === 'video'),\n isAudio: (props.mediaType === 'audio'),\n isLink: (props.mediaType === 'link'),\n isUpdating: props.isUpdating,\n };\n\n if (props.mediaData) {\n return {\n ...context,\n ...props.mediaData,\n };\n } else {\n return {\n ...context,\n ...await props.mediaTemplateContext,\n };\n }\n};\n\n/**\n * Get help strings.\n *\n * @returns {object}\n */\nexport const getHelpStrings = async() => {\n const [\n customsize,\n ] = await getStrings([\n 'customsize_help',\n ].map((key) => ({\n key,\n component,\n })));\n\n return {\n customsize,\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: querySelector(Selectors.EMBED.elements.videoTag).getAttribute('poster'),\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"],"names":["props","mediaType","showDropzone","canShowDropZone","showFilePicker","canShowFilePicker","editor","selectedMedia","mediaElm","selection","getNode","nodeName","toLowerCase","querySelector","url","params","includes","Selectors","EMBED","mediaSites","youtube","fetchedUrl","fetchedUrlValue","k","replace","state","sites","site","async","context","bodyTemplate","template","body","mediaDetailsBody","footerTemplate","footer","mediaDetailsFooter","isVideo","isAudio","isLink","isUpdating","mediaData","mediaTemplateContext","customsize","map","key","component","moodleLangs","currentLanguage","installed","Object","entries","_ref","lang","code","available","_ref2","subtitleLang","tracks","subtitles","captions","descriptions","chapters","metadata","root","querySelectorAll","elements","mediaMetadataTabPane","forEach","metaData","track","dataset","trackKind","push","src","value","srclang","trackLang","label","trackLabel","defaultTrack","trackDefault","checked","element","mediaDataProps","media","type","sources","poster","videoTag","getAttribute","title","width","height","autoplay","mediaAutoplay","loop","mediaLoop","muted","mediaMute","controls","mediaControl","link"],"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 {\n convertStringUrlToObject,\n createUrlParams,\n} from '../helpers';\nimport {getStrings} from 'core/str';\nimport {component} from \"../common\";\nimport {\n getCurrentLanguage,\n getMoodleLang\n} from 'editor_tiny/options';\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 };\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.nodeName.toLowerCase() === 'a') {\n mediaType = 'link';\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 }\n\n return [mediaType, selectedMedia];\n};\n\n/**\n * Format url when inserting media link to be previewed.\n *\n * @param {string} url\n * @returns {string}\n */\nexport const formatMediaUrl = (url) => {\n // Convert the string url into url param object.\n const params = convertStringUrlToObject(url);\n\n // Format the url for youtube links.\n if (url.includes(Selectors.EMBED.mediaSites.youtube)) {\n let fetchedUrl = null;\n let fetchedUrlValue = null;\n for (const k in params) {\n if (url.includes(k)) {\n fetchedUrl = k;\n fetchedUrlValue = params[k];\n delete params[k];\n break;\n }\n }\n url = fetchedUrl.replace('watch?v', 'embed/');\n url = url + fetchedUrlValue + '?' + createUrlParams(params);\n }\n return url;\n};\n\n/**\n * Check if the url is from a known media site.\n *\n * @param {string} url\n * @returns {boolean}\n */\nexport const isUrlFromKnownMediaSites = (url) => {\n let state = false;\n const sites = Selectors.EMBED.mediaSites;\n for (const site in sites) {\n if (url.includes(sites[site])) {\n state = true;\n break;\n }\n }\n return state;\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 isVideo: (props.mediaType === 'video'),\n isAudio: (props.mediaType === 'audio'),\n isLink: (props.mediaType === 'link'),\n isUpdating: props.isUpdating,\n };\n\n if (props.mediaData) {\n return {\n ...context,\n ...props.mediaData,\n };\n } else {\n return {\n ...context,\n ...await props.mediaTemplateContext,\n };\n }\n};\n\n/**\n * Get help strings.\n *\n * @returns {object}\n */\nexport const getHelpStrings = async() => {\n const [\n customsize,\n ] = await getStrings([\n 'customsize_help',\n ].map((key) => ({\n key,\n component,\n })));\n\n return {\n customsize,\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: querySelector(Selectors.EMBED.elements.videoTag).getAttribute('poster'),\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 * Get based url from the link.\n *\n * @param {string} url\n * @returns {string}\n */\nexport const getLinkBasedUrl = (url) => {\n if (url.includes(Selectors.EMBED.mediaSites.youtube)) {\n if (url.includes('embed/')) {\n const urlParams = url.split('embed/');\n let id = null;\n if (urlParams[1].includes('?')) {\n id = urlParams[1].split('?')[0];\n } else {\n id = urlParams[1];\n }\n url = `${urlParams[0]}watch?v=${id}&`;\n }\n }\n return url;\n};\n"],"names":["props","mediaType","showDropzone","canShowDropZone","showFilePicker","canShowFilePicker","editor","selectedMedia","mediaElm","selection","getNode","nodeName","toLowerCase","querySelector","url","params","includes","Selectors","EMBED","mediaSites","youtube","fetchedUrl","fetchedUrlValue","k","replace","state","sites","site","async","context","bodyTemplate","template","body","mediaDetailsBody","footerTemplate","footer","mediaDetailsFooter","isVideo","isAudio","isLink","isUpdating","mediaData","mediaTemplateContext","customsize","map","key","component","moodleLangs","currentLanguage","installed","Object","entries","_ref","lang","code","available","_ref2","subtitleLang","tracks","subtitles","captions","descriptions","chapters","metadata","root","querySelectorAll","elements","mediaMetadataTabPane","forEach","metaData","track","dataset","trackKind","push","src","value","srclang","trackLang","label","trackLabel","defaultTrack","trackDefault","checked","element","mediaDataProps","media","type","sources","poster","videoTag","getAttribute","title","width","height","autoplay","mediaAutoplay","loop","mediaLoop","muted","mediaMute","controls","mediaControl","link","urlParams","split","id"],"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 1d4795c635b..25f37367847 100644 --- a/lib/editor/tiny/plugins/media/amd/src/embed/embedhandler.js +++ b/lib/editor/tiny/plugins/media/amd/src/embed/embedhandler.js @@ -39,6 +39,7 @@ import { isValidUrl, convertStringUrlToObject, stopMediaLoading, + createUrlParams, } from '../helpers'; import * as ModalEvents from 'core/modal_events'; import {displayFilepicker} from 'editor_tiny/utils'; @@ -47,7 +48,9 @@ import { getHelpStrings, prepareMoodleLang, getMoodleLangObj, + getLinkBasedUrl, } from "./embedhelpers"; +import Templates from 'core/templates'; export class EmbedHandler { @@ -413,6 +416,119 @@ export class EmbedHandler { addUrl.disabled = !(url !== "" && isValidUrl(url)); } + /** + * Get media html to be inserted or updated into tiny. + * + * @param {html} form Selected element + * @returns {string} String of html + */ + getMediaHTML = (form) => { + let mediumType = this.root.querySelector(Selectors.EMBED.elements.previewClass).nodeName.toLowerCase(); + mediumType = (mediumType === 'iframe') ? 'link' : mediumType; + const tabContent = form.querySelector('.tab-content'); + const callback = 'getMediaHTML' + mediumType[0].toUpperCase() + mediumType.substr(1); + return this[callback](tabContent); + }; + + /** + * Get media as link. + * + * @returns {string} String of html + */ + getMediaHTMLLink = () => { + const details = document.querySelector(Selectors.EMBED.elements.mediaDetailsBody); + const url = details.querySelector(Selectors.EMBED.elements.preview).src ?? null; + const urlParamString = createUrlParams({ + controls: details.querySelector(Selectors.EMBED.elements.mediaControl).checked ? 1 : 0, + autoplay: details.querySelector(Selectors.EMBED.elements.mediaAutoplay).checked ? 1 : 0, + mute: details.querySelector(Selectors.EMBED.elements.mediaMute).checked ? 1 : 0, + }); + const name = details.querySelector(Selectors.EMBED.elements.title).value || false; + const context = { + url: getLinkBasedUrl(url) + urlParamString, + name: name ? name.trim() : false, + }; + + return context.url ? Templates.renderForPromise('tiny_media/embed/embed_media_link', context) : ''; + }; + + /** + * Get media as video. + * + * @param {html} tab Selected element + * @returns {string} String of html. + */ + getMediaHTMLVideo = (tab) => { + const details = document.querySelector(Selectors.EMBED.elements.mediaDetailsBody); + const context = this.getContextForMediaHTML(tab, details); + context.width = details.querySelector(Selectors.EMBED.elements.width).value || false; + context.height = details.querySelector(Selectors.EMBED.elements.height).value || false; + context.poster = details.querySelector(Selectors.EMBED.elements.videoTag).poster || false; + return context.sources ? Templates.renderForPromise('tiny_media/embed/embed_media_video', context) : ''; + }; + + /** + * Get media as audio. + * + * @param {html} tab Selected element + * @returns {string} String of html. + */ + getMediaHTMLAudio = (tab) => { + const details = document.querySelector(Selectors.EMBED.elements.mediaDetailsBody); + const context = this.getContextForMediaHTML(tab, details); + return context.sources.length ? Templates.renderForPromise('tiny_media/embed/embed_media_audio', context) : ''; + }; + + /** + * Get previewed media data. + * + * @param {html} tab Selected element + * @param {html} details Selected element + * @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 sources = details.querySelector(Selectors.EMBED.elements.preview).src ?? null; + const title = details.querySelector(Selectors.EMBED.elements.title).value; + + return { + sources, + description: tab.querySelector(Selectors.EMBED.elements.url).value || false, + tracks, + showControls: details.querySelector(Selectors.EMBED.elements.mediaControl).checked, + autoplay: details.querySelector(Selectors.EMBED.elements.mediaAutoplay).checked, + muted: details.querySelector(Selectors.EMBED.elements.mediaMute).checked, + loop: details.querySelector(Selectors.EMBED.elements.mediaLoop).checked, + title: title !== '' ? title.trim() : false, + }; + }; + + /** + * Handle the insert/update media in tiny editor. + * + * @param {event} event + * @param {object} modal Object of current modal + */ + handleDialogueSubmission = async(event, modal) => { + const {html} = await this.getMediaHTML(modal.getRoot()[0]); + if (html) { + if (this.isUpdating) { + this.selectedMedia.outerHTML = html; + this.isUpdating = false; + } else { + this.editor.insertContent(html); + } + } + }; + registerEventListeners = async(modal) => { await modal.getBody(); const $root = modal.getRoot(); @@ -440,5 +556,7 @@ export class EmbedHandler { } }); }); + + $root.on(ModalEvents.save, this.handleDialogueSubmission.bind(this)); }; } 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 64414742edb..6971520d092 100644 --- a/lib/editor/tiny/plugins/media/amd/src/embed/embedhelpers.js +++ b/lib/editor/tiny/plugins/media/amd/src/embed/embedhelpers.js @@ -269,3 +269,25 @@ export const getEmbeddedMediaDetails = (props) => { mediaDataProps.link = false; return mediaDataProps; }; + +/** + * Get based url from the link. + * + * @param {string} url + * @returns {string} + */ +export const getLinkBasedUrl = (url) => { + if (url.includes(Selectors.EMBED.mediaSites.youtube)) { + if (url.includes('embed/')) { + const urlParams = url.split('embed/'); + let id = null; + if (urlParams[1].includes('?')) { + id = urlParams[1].split('?')[0]; + } else { + id = urlParams[1]; + } + url = `${urlParams[0]}watch?v=${id}&`; + } + } + return url; +}; diff --git a/lib/editor/tiny/plugins/media/templates/embed/footer/media_details_footer.mustache b/lib/editor/tiny/plugins/media/templates/embed/footer/media_details_footer.mustache index c89a0be9395..051088983e8 100644 --- a/lib/editor/tiny/plugins/media/templates/embed/footer/media_details_footer.mustache +++ b/lib/editor/tiny/plugins/media/templates/embed/footer/media_details_footer.mustache @@ -46,6 +46,9 @@
+
{{/isLink}}