diff --git a/lib/editor/tiny/plugins/media/amd/build/image.min.js b/lib/editor/tiny/plugins/media/amd/build/image.min.js index 93f5118b57291..78bd5f13d0143 100644 --- a/lib/editor/tiny/plugins/media/amd/build/image.min.js +++ b/lib/editor/tiny/plugins/media/amd/build/image.min.js @@ -1,3 +1,3 @@ -define("tiny_media/image",["exports","./selectors","./imagemodal","./options","editor_tiny/options","tiny_media/imageinsert","tiny_media/imagedetails","core/str","tiny_media/imagehelpers"],(function(_exports,_selectors,_imagemodal,_options,_options2,_imageinsert,_imagedetails,_str,_imagehelpers){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_selectors=_interopRequireDefault(_selectors),_imagemodal=_interopRequireDefault(_imagemodal);return _exports.default=class{constructor(editor){_defineProperty(this,"canShowFilePicker",!1),_defineProperty(this,"editor",null),_defineProperty(this,"currentModal",null),_defineProperty(this,"root",null),_defineProperty(this,"loadInsertImage",(async function(){const templateContext={elementid:this.editor.id,showfilepicker:this.canShowFilePicker,showdropzone:this.canShowDropZone};Promise.all([(0,_imagehelpers.bodyImageInsert)(templateContext,this.root),(0,_imagehelpers.footerImageInsert)(templateContext,this.root)]).then((()=>{new _imageinsert.ImageInsert(this.root,this.editor,this.currentModal,this.canShowFilePicker,this.canShowDropZone).init()})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"loadPreviewImage",(async function(url){this.startImageLoading();const image=new Image;image.src=url,image.addEventListener("error",(()=>{this.root.querySelector(_selectors.default.IMAGE.elements.urlWarning).innerHTML=this.langStrings.imageurlrequired,(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.urlWarning,this.root),this.stopImageLoading()})),image.addEventListener("load",(async()=>{const currentImageData=await this.getCurrentImageData();let templateContext=await this.getTemplateContext(currentImageData);templateContext.sizecustomhelpicon={text:await(0,_str.getString)("sizecustom_help","tiny_media")},Promise.all([(0,_imagehelpers.bodyImageDetails)(templateContext,this.root),(0,_imagehelpers.footerImageDetails)(templateContext,this.root)]).then((()=>{this.stopImageLoading()})).then((()=>{new _imagedetails.ImageDetails(this.root,this.editor,this.currentModal,this.canShowFilePicker,this.canShowDropZone,url,image).init()})).catch((error=>{window.console.log(error)}))}))}));const permissions=(0,_options.getImagePermissions)(editor),options=(0,_options2.getFilePicker)(editor,"image");this.canShowFilePicker=permissions.filepicker&&void 0!==options&&Object.keys(options.repositories).length>0,this.canShowDropZone=void 0!==options&&Object.values(options.repositories).some((repository=>"upload"===repository.type)),this.editor=editor}async displayDialogue(){const currentImageData=await this.getCurrentImageData();this.currentModal=await _imagemodal.default.create(),this.root=this.currentModal.getRoot()[0],currentImageData&¤tImageData.src?this.loadPreviewImage(currentImageData.src):this.loadInsertImage()}async getTemplateContext(data){return{elementid:this.editor.id,showfilepicker:this.canShowFilePicker,...data}}async getCurrentImageData(){const selectedImageProperties=this.getSelectedImageProperties();if(!selectedImageProperties)return{};const properties={...selectedImageProperties};return properties.src&&(properties.haspreview=!0),properties.alt||(properties.presentation=!0),properties}getSelectedImageProperties(){const image=this.getSelectedImage();if(!image)return this.selectedImage=null,null;const properties={src:null,alt:null,width:null,height:null,presentation:!1,customStyle:""};this.selectedImage=image,properties.customStyle=image.style.cssText;const width=(image=>(0,_imagehelpers.isPercentageValue)(String(image.width))?image.width:parseInt(image.width,10))(image);0!==width&&(properties.width=width);const height=(image=>(0,_imagehelpers.isPercentageValue)(String(image.height))?image.height:parseInt(image.height,10))(image);return 0!==height&&(properties.height=height),properties.src=image.getAttribute("src"),properties.alt=image.getAttribute("alt")||"",properties.presentation="presentation"===image.getAttribute("role"),properties}getSelectedImage(){const imgElm=this.editor.selection.getNode(),figureElm=this.editor.dom.getParent(imgElm,"figure.image");return figureElm?this.editor.dom.select("img",figureElm)[0]:imgElm&&("IMG"!==imgElm.nodeName.toUpperCase()||this.isPlaceholderImage(imgElm))?null:imgElm}isPlaceholderImage(imgElm){return"IMG"===imgElm.nodeName.toUpperCase()&&(imgElm.hasAttribute("data-mce-object")||imgElm.hasAttribute("data-mce-placeholder"))}startImageLoading(){(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.loaderIcon,this.root),(0,_imagehelpers.hideElements)(_selectors.default.IMAGE.elements.insertImage,this.root)}stopImageLoading(){(0,_imagehelpers.hideElements)(_selectors.default.IMAGE.elements.loaderIcon,this.root),(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.insertImage,this.root)}},_exports.default})); +define("tiny_media/image",["exports","./selectors","./imagemodal","./options","editor_tiny/options","tiny_media/imageinsert","tiny_media/imagedetails","core/prefetch","core/str","tiny_media/imagehelpers"],(function(_exports,_selectors,_imagemodal,_options,_options2,_imageinsert,_imagedetails,_prefetch,_str,_imagehelpers){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_selectors=_interopRequireDefault(_selectors),_imagemodal=_interopRequireDefault(_imagemodal),(0,_prefetch.prefetchStrings)("tiny_media",["imageurlrequired","sizecustom_help"]);return _exports.default=class{constructor(editor){_defineProperty(this,"canShowFilePicker",!1),_defineProperty(this,"editor",null),_defineProperty(this,"currentModal",null),_defineProperty(this,"root",null),_defineProperty(this,"loadInsertImage",(async function(){const templateContext={elementid:this.editor.id,showfilepicker:this.canShowFilePicker,showdropzone:this.canShowDropZone};Promise.all([(0,_imagehelpers.bodyImageInsert)(templateContext,this.root),(0,_imagehelpers.footerImageInsert)(templateContext,this.root)]).then((()=>{new _imageinsert.ImageInsert(this.root,this.editor,this.currentModal,this.canShowFilePicker,this.canShowDropZone).init()})).catch((error=>{window.console.log(error)}))})),_defineProperty(this,"loadPreviewImage",(async function(url){this.startImageLoading();const image=new Image;image.src=url,image.addEventListener("error",(async()=>{this.root.querySelector(_selectors.default.IMAGE.elements.urlWarning).innerHTML=await(0,_str.getString)("imageurlrequired","tiny_media"),(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.urlWarning,this.root),this.stopImageLoading()})),image.addEventListener("load",(async()=>{const currentImageData=await this.getCurrentImageData();let templateContext=await this.getTemplateContext(currentImageData);templateContext.sizecustomhelpicon={text:await(0,_str.getString)("sizecustom_help","tiny_media")},Promise.all([(0,_imagehelpers.bodyImageDetails)(templateContext,this.root),(0,_imagehelpers.footerImageDetails)(templateContext,this.root)]).then((()=>{this.stopImageLoading()})).then((()=>{new _imagedetails.ImageDetails(this.root,this.editor,this.currentModal,this.canShowFilePicker,this.canShowDropZone,url,image).init()})).catch((error=>{window.console.log(error)}))}))}));const permissions=(0,_options.getImagePermissions)(editor),options=(0,_options2.getFilePicker)(editor,"image");this.canShowFilePicker=permissions.filepicker&&void 0!==options&&Object.keys(options.repositories).length>0,this.canShowDropZone=void 0!==options&&Object.values(options.repositories).some((repository=>"upload"===repository.type)),this.editor=editor}async displayDialogue(){const currentImageData=await this.getCurrentImageData();this.currentModal=await _imagemodal.default.create(),this.root=this.currentModal.getRoot()[0],currentImageData&¤tImageData.src?this.loadPreviewImage(currentImageData.src):this.loadInsertImage()}async getTemplateContext(data){return{elementid:this.editor.id,showfilepicker:this.canShowFilePicker,...data}}async getCurrentImageData(){const selectedImageProperties=this.getSelectedImageProperties();if(!selectedImageProperties)return{};const properties={...selectedImageProperties};return properties.src&&(properties.haspreview=!0),properties.alt||(properties.presentation=!0),properties}getSelectedImageProperties(){const image=this.getSelectedImage();if(!image)return this.selectedImage=null,null;const properties={src:null,alt:null,width:null,height:null,presentation:!1,customStyle:""};this.selectedImage=image,properties.customStyle=image.style.cssText;const width=(image=>(0,_imagehelpers.isPercentageValue)(String(image.width))?image.width:parseInt(image.width,10))(image);0!==width&&(properties.width=width);const height=(image=>(0,_imagehelpers.isPercentageValue)(String(image.height))?image.height:parseInt(image.height,10))(image);return 0!==height&&(properties.height=height),properties.src=image.getAttribute("src"),properties.alt=image.getAttribute("alt")||"",properties.presentation="presentation"===image.getAttribute("role"),properties}getSelectedImage(){const imgElm=this.editor.selection.getNode(),figureElm=this.editor.dom.getParent(imgElm,"figure.image");return figureElm?this.editor.dom.select("img",figureElm)[0]:imgElm&&("IMG"!==imgElm.nodeName.toUpperCase()||this.isPlaceholderImage(imgElm))?null:imgElm}isPlaceholderImage(imgElm){return"IMG"===imgElm.nodeName.toUpperCase()&&(imgElm.hasAttribute("data-mce-object")||imgElm.hasAttribute("data-mce-placeholder"))}startImageLoading(){(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.loaderIcon,this.root),(0,_imagehelpers.hideElements)(_selectors.default.IMAGE.elements.insertImage,this.root)}stopImageLoading(){(0,_imagehelpers.hideElements)(_selectors.default.IMAGE.elements.loaderIcon,this.root),(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.insertImage,this.root)}},_exports.default})); //# sourceMappingURL=image.min.js.map \ No newline at end of file diff --git a/lib/editor/tiny/plugins/media/amd/build/image.min.js.map b/lib/editor/tiny/plugins/media/amd/build/image.min.js.map index 08dc1b4d5286b..be8dbf883b324 100644 --- a/lib/editor/tiny/plugins/media/amd/build/image.min.js.map +++ b/lib/editor/tiny/plugins/media/amd/build/image.min.js.map @@ -1 +1 @@ -{"version":3,"file":"image.min.js","sources":["../src/image.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 Image class for Moodle.\n *\n * @module tiny_media/image\n * @copyright 2022 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from './selectors';\nimport ImageModal from './imagemodal';\nimport {getImagePermissions} from './options';\nimport {getFilePicker} from 'editor_tiny/options';\nimport {ImageInsert} from 'tiny_media/imageinsert';\nimport {ImageDetails} from 'tiny_media/imagedetails';\nimport {getString} from 'core/str';\nimport {\n bodyImageInsert,\n footerImageInsert,\n bodyImageDetails,\n footerImageDetails,\n showElements,\n hideElements,\n isPercentageValue,\n} from 'tiny_media/imagehelpers';\n\nexport default class MediaImage {\n canShowFilePicker = false;\n editor = null;\n currentModal = null;\n /**\n * @type {HTMLElement|null} The root element.\n */\n root = null;\n\n constructor(editor) {\n const permissions = getImagePermissions(editor);\n const options = getFilePicker(editor, 'image');\n // Indicates whether the file picker can be shown.\n this.canShowFilePicker = permissions.filepicker\n && (typeof options !== 'undefined')\n && Object.keys(options.repositories).length > 0;\n // Indicates whether the drop zone area can be shown.\n this.canShowDropZone = (typeof options !== 'undefined') &&\n Object.values(options.repositories).some(repository => repository.type === 'upload');\n\n this.editor = editor;\n }\n\n async displayDialogue() {\n const currentImageData = await this.getCurrentImageData();\n this.currentModal = await ImageModal.create();\n this.root = this.currentModal.getRoot()[0];\n if (currentImageData && currentImageData.src) {\n this.loadPreviewImage(currentImageData.src);\n } else {\n this.loadInsertImage();\n }\n }\n\n /**\n * Displays an insert image view asynchronously.\n *\n * @returns {Promise}\n */\n loadInsertImage = async function() {\n const templateContext = {\n elementid: this.editor.id,\n showfilepicker: this.canShowFilePicker,\n showdropzone: this.canShowDropZone,\n };\n\n Promise.all([bodyImageInsert(templateContext, this.root), footerImageInsert(templateContext, this.root)])\n .then(() => {\n const imageinsert = new ImageInsert(\n this.root,\n this.editor,\n this.currentModal,\n this.canShowFilePicker,\n this.canShowDropZone,\n );\n imageinsert.init();\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n };\n\n async getTemplateContext(data) {\n return {\n elementid: this.editor.id,\n showfilepicker: this.canShowFilePicker,\n ...data,\n };\n }\n\n async getCurrentImageData() {\n const selectedImageProperties = this.getSelectedImageProperties();\n if (!selectedImageProperties) {\n return {};\n }\n\n const properties = {...selectedImageProperties};\n\n if (properties.src) {\n properties.haspreview = true;\n }\n\n if (!properties.alt) {\n properties.presentation = true;\n }\n\n return properties;\n }\n\n /**\n * Asynchronously loads and previews an image from the provided URL.\n *\n * @param {string} url - The URL of the image to load and preview.\n * @returns {Promise}\n */\n loadPreviewImage = async function(url) {\n this.startImageLoading();\n const image = new Image();\n image.src = url;\n image.addEventListener('error', () => {\n const urlWarningLabelEle = this.root.querySelector(Selectors.IMAGE.elements.urlWarning);\n urlWarningLabelEle.innerHTML = this.langStrings.imageurlrequired;\n showElements(Selectors.IMAGE.elements.urlWarning, this.root);\n this.stopImageLoading();\n });\n\n image.addEventListener('load', async() => {\n const currentImageData = await this.getCurrentImageData();\n let templateContext = await this.getTemplateContext(currentImageData);\n templateContext.sizecustomhelpicon = {text: await getString('sizecustom_help', 'tiny_media')};\n\n Promise.all([bodyImageDetails(templateContext, this.root), footerImageDetails(templateContext, this.root)])\n .then(() => {\n this.stopImageLoading();\n return;\n })\n .then(() => {\n const imagedetails = new ImageDetails(\n this.root,\n this.editor,\n this.currentModal,\n this.canShowFilePicker,\n this.canShowDropZone,\n url,\n image,\n );\n imagedetails.init();\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n });\n };\n\n getSelectedImageProperties() {\n const image = this.getSelectedImage();\n if (!image) {\n this.selectedImage = null;\n return null;\n }\n\n const properties = {\n src: null,\n alt: null,\n width: null,\n height: null,\n presentation: false,\n customStyle: '', // Custom CSS styles applied to the image.\n };\n\n const getImageHeight = (image) => {\n if (!isPercentageValue(String(image.height))) {\n return parseInt(image.height, 10);\n }\n\n return image.height;\n };\n\n const getImageWidth = (image) => {\n if (!isPercentageValue(String(image.width))) {\n return parseInt(image.width, 10);\n }\n\n return image.width;\n };\n\n // Get the current selection.\n this.selectedImage = image;\n\n properties.customStyle = image.style.cssText;\n\n const width = getImageWidth(image);\n if (width !== 0) {\n properties.width = width;\n }\n\n const height = getImageHeight(image);\n if (height !== 0) {\n properties.height = height;\n }\n\n properties.src = image.getAttribute('src');\n properties.alt = image.getAttribute('alt') || '';\n properties.presentation = (image.getAttribute('role') === 'presentation');\n\n return properties;\n }\n\n getSelectedImage() {\n const imgElm = this.editor.selection.getNode();\n const figureElm = this.editor.dom.getParent(imgElm, 'figure.image');\n if (figureElm) {\n return this.editor.dom.select('img', figureElm)[0];\n }\n\n if (imgElm && (imgElm.nodeName.toUpperCase() !== 'IMG' || this.isPlaceholderImage(imgElm))) {\n return null;\n }\n return imgElm;\n }\n\n isPlaceholderImage(imgElm) {\n if (imgElm.nodeName.toUpperCase() !== 'IMG') {\n return false;\n }\n\n return (imgElm.hasAttribute('data-mce-object') || imgElm.hasAttribute('data-mce-placeholder'));\n }\n\n /**\n * Displays the upload loader and disables UI elements while loading a file.\n */\n startImageLoading() {\n showElements(Selectors.IMAGE.elements.loaderIcon, this.root);\n hideElements(Selectors.IMAGE.elements.insertImage, this.root);\n }\n\n /**\n * Displays the upload loader and disables UI elements while loading a file.\n */\n stopImageLoading() {\n hideElements(Selectors.IMAGE.elements.loaderIcon, this.root);\n showElements(Selectors.IMAGE.elements.insertImage, this.root);\n }\n}\n"],"names":["constructor","editor","async","templateContext","elementid","this","id","showfilepicker","canShowFilePicker","showdropzone","canShowDropZone","Promise","all","root","then","ImageInsert","currentModal","init","catch","error","window","console","log","url","startImageLoading","image","Image","src","addEventListener","querySelector","Selectors","IMAGE","elements","urlWarning","innerHTML","langStrings","imageurlrequired","stopImageLoading","currentImageData","getCurrentImageData","getTemplateContext","sizecustomhelpicon","text","ImageDetails","permissions","options","filepicker","Object","keys","repositories","length","values","some","repository","type","ImageModal","create","getRoot","loadPreviewImage","loadInsertImage","data","selectedImageProperties","getSelectedImageProperties","properties","haspreview","alt","presentation","getSelectedImage","selectedImage","width","height","customStyle","style","cssText","String","parseInt","getImageWidth","getImageHeight","getAttribute","imgElm","selection","getNode","figureElm","dom","getParent","select","nodeName","toUpperCase","isPlaceholderImage","hasAttribute","loaderIcon","insertImage"],"mappings":"2uBAiDIA,YAAYC,kDARQ,iCACX,0CACM,kCAIR,8CAgCWC,uBACRC,gBAAkB,CACpBC,UAAWC,KAAKJ,OAAOK,GACvBC,eAAgBF,KAAKG,kBACrBC,aAAcJ,KAAKK,iBAGvBC,QAAQC,IAAI,EAAC,iCAAgBT,gBAAiBE,KAAKQ,OAAO,mCAAkBV,gBAAiBE,KAAKQ,QAC7FC,MAAK,KACkB,IAAIC,yBACpBV,KAAKQ,KACLR,KAAKJ,OACLI,KAAKW,aACLX,KAAKG,kBACLH,KAAKK,iBAEGO,UAGfC,OAAMC,QACHC,OAAOC,QAAQC,IAAIH,sDAqCZjB,eAAeqB,UACzBC,0BACCC,MAAQ,IAAIC,MAClBD,MAAME,IAAMJ,IACZE,MAAMG,iBAAiB,SAAS,KACDvB,KAAKQ,KAAKgB,cAAcC,mBAAUC,MAAMC,SAASC,YACzDC,UAAY7B,KAAK8B,YAAYC,gDACnCN,mBAAUC,MAAMC,SAASC,WAAY5B,KAAKQ,WAClDwB,sBAGTZ,MAAMG,iBAAiB,QAAQ1B,gBACrBoC,uBAAyBjC,KAAKkC,0BAChCpC,sBAAwBE,KAAKmC,mBAAmBF,kBACpDnC,gBAAgBsC,mBAAqB,CAACC,WAAY,kBAAU,kBAAmB,eAE/E/B,QAAQC,IAAI,EAAC,kCAAiBT,gBAAiBE,KAAKQ,OAAO,oCAAmBV,gBAAiBE,KAAKQ,QAC/FC,MAAK,UACGuB,sBAGRvB,MAAK,KACmB,IAAI6B,2BACrBtC,KAAKQ,KACLR,KAAKJ,OACLI,KAAKW,aACLX,KAAKG,kBACLH,KAAKK,gBACLa,IACAE,OAESR,UAGhBC,OAAMC,QACHC,OAAOC,QAAQC,IAAIH,sBAzHzByB,aAAc,gCAAoB3C,QAClC4C,SAAU,2BAAc5C,OAAQ,cAEjCO,kBAAoBoC,YAAYE,iBACV,IAAZD,SACRE,OAAOC,KAAKH,QAAQI,cAAcC,OAAS,OAE7CxC,qBAAsC,IAAZmC,SAC3BE,OAAOI,OAAON,QAAQI,cAAcG,MAAKC,YAAkC,WAApBA,WAAWC,YAEjErD,OAASA,qCAIRqC,uBAAyBjC,KAAKkC,2BAC/BvB,mBAAqBuC,oBAAWC,cAChC3C,KAAOR,KAAKW,aAAayC,UAAU,GACpCnB,kBAAoBA,iBAAiBX,SAChC+B,iBAAiBpB,iBAAiBX,UAElCgC,2CAiCYC,YACd,CACHxD,UAAWC,KAAKJ,OAAOK,GACvBC,eAAgBF,KAAKG,qBAClBoD,wCAKDC,wBAA0BxD,KAAKyD,iCAChCD,8BACM,SAGLE,WAAa,IAAIF,gCAEnBE,WAAWpC,MACXoC,WAAWC,YAAa,GAGvBD,WAAWE,MACZF,WAAWG,cAAe,GAGvBH,WAiDXD,mCACUrC,MAAQpB,KAAK8D,uBACd1C,kBACI2C,cAAgB,KACd,WAGLL,WAAa,CACfpC,IAAK,KACLsC,IAAK,KACLI,MAAO,KACPC,OAAQ,KACRJ,cAAc,EACdK,YAAa,SAoBZH,cAAgB3C,MAErBsC,WAAWQ,YAAc9C,MAAM+C,MAAMC,cAE/BJ,MAbiB5C,CAAAA,QACd,mCAAkBiD,OAAOjD,MAAM4C,QAI7B5C,MAAM4C,MAHFM,SAASlD,MAAM4C,MAAO,IAWvBO,CAAcnD,OACd,IAAV4C,QACAN,WAAWM,MAAQA,aAGjBC,OA1BkB7C,CAAAA,QACf,mCAAkBiD,OAAOjD,MAAM6C,SAI7B7C,MAAM6C,OAHFK,SAASlD,MAAM6C,OAAQ,IAwBvBO,CAAepD,cACf,IAAX6C,SACAP,WAAWO,OAASA,QAGxBP,WAAWpC,IAAMF,MAAMqD,aAAa,OACpCf,WAAWE,IAAMxC,MAAMqD,aAAa,QAAU,GAC9Cf,WAAWG,aAA+C,iBAA/BzC,MAAMqD,aAAa,QAEvCf,WAGXI,yBACUY,OAAS1E,KAAKJ,OAAO+E,UAAUC,UAC/BC,UAAY7E,KAAKJ,OAAOkF,IAAIC,UAAUL,OAAQ,uBAChDG,UACO7E,KAAKJ,OAAOkF,IAAIE,OAAO,MAAOH,WAAW,GAGhDH,SAA6C,QAAlCA,OAAOO,SAASC,eAA2BlF,KAAKmF,mBAAmBT,SACvE,KAEJA,OAGXS,mBAAmBT,cACuB,QAAlCA,OAAOO,SAASC,gBAIZR,OAAOU,aAAa,oBAAsBV,OAAOU,aAAa,yBAM1EjE,mDACiBM,mBAAUC,MAAMC,SAAS0D,WAAYrF,KAAKQ,qCAC1CiB,mBAAUC,MAAMC,SAAS2D,YAAatF,KAAKQ,MAM5DwB,kDACiBP,mBAAUC,MAAMC,SAAS0D,WAAYrF,KAAKQ,qCAC1CiB,mBAAUC,MAAMC,SAAS2D,YAAatF,KAAKQ"} \ No newline at end of file +{"version":3,"file":"image.min.js","sources":["../src/image.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 Image class for Moodle.\n *\n * @module tiny_media/image\n * @copyright 2022 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from './selectors';\nimport ImageModal from './imagemodal';\nimport {getImagePermissions} from './options';\nimport {getFilePicker} from 'editor_tiny/options';\nimport {ImageInsert} from 'tiny_media/imageinsert';\nimport {ImageDetails} from 'tiny_media/imagedetails';\nimport {prefetchStrings} from 'core/prefetch';\nimport {getString} from 'core/str';\nimport {\n bodyImageInsert,\n footerImageInsert,\n bodyImageDetails,\n footerImageDetails,\n showElements,\n hideElements,\n isPercentageValue,\n} from 'tiny_media/imagehelpers';\n\nprefetchStrings('tiny_media', [\n 'imageurlrequired',\n 'sizecustom_help',\n]);\n\nexport default class MediaImage {\n canShowFilePicker = false;\n editor = null;\n currentModal = null;\n /**\n * @type {HTMLElement|null} The root element.\n */\n root = null;\n\n constructor(editor) {\n const permissions = getImagePermissions(editor);\n const options = getFilePicker(editor, 'image');\n // Indicates whether the file picker can be shown.\n this.canShowFilePicker = permissions.filepicker\n && (typeof options !== 'undefined')\n && Object.keys(options.repositories).length > 0;\n // Indicates whether the drop zone area can be shown.\n this.canShowDropZone = (typeof options !== 'undefined') &&\n Object.values(options.repositories).some(repository => repository.type === 'upload');\n\n this.editor = editor;\n }\n\n async displayDialogue() {\n const currentImageData = await this.getCurrentImageData();\n this.currentModal = await ImageModal.create();\n this.root = this.currentModal.getRoot()[0];\n if (currentImageData && currentImageData.src) {\n this.loadPreviewImage(currentImageData.src);\n } else {\n this.loadInsertImage();\n }\n }\n\n /**\n * Displays an insert image view asynchronously.\n *\n * @returns {Promise}\n */\n loadInsertImage = async function() {\n const templateContext = {\n elementid: this.editor.id,\n showfilepicker: this.canShowFilePicker,\n showdropzone: this.canShowDropZone,\n };\n\n Promise.all([bodyImageInsert(templateContext, this.root), footerImageInsert(templateContext, this.root)])\n .then(() => {\n const imageinsert = new ImageInsert(\n this.root,\n this.editor,\n this.currentModal,\n this.canShowFilePicker,\n this.canShowDropZone,\n );\n imageinsert.init();\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n };\n\n async getTemplateContext(data) {\n return {\n elementid: this.editor.id,\n showfilepicker: this.canShowFilePicker,\n ...data,\n };\n }\n\n async getCurrentImageData() {\n const selectedImageProperties = this.getSelectedImageProperties();\n if (!selectedImageProperties) {\n return {};\n }\n\n const properties = {...selectedImageProperties};\n\n if (properties.src) {\n properties.haspreview = true;\n }\n\n if (!properties.alt) {\n properties.presentation = true;\n }\n\n return properties;\n }\n\n /**\n * Asynchronously loads and previews an image from the provided URL.\n *\n * @param {string} url - The URL of the image to load and preview.\n * @returns {Promise}\n */\n loadPreviewImage = async function(url) {\n this.startImageLoading();\n const image = new Image();\n image.src = url;\n image.addEventListener('error', async() => {\n const urlWarningLabelEle = this.root.querySelector(Selectors.IMAGE.elements.urlWarning);\n urlWarningLabelEle.innerHTML = await getString('imageurlrequired', 'tiny_media');\n showElements(Selectors.IMAGE.elements.urlWarning, this.root);\n this.stopImageLoading();\n });\n\n image.addEventListener('load', async() => {\n const currentImageData = await this.getCurrentImageData();\n let templateContext = await this.getTemplateContext(currentImageData);\n templateContext.sizecustomhelpicon = {text: await getString('sizecustom_help', 'tiny_media')};\n\n Promise.all([bodyImageDetails(templateContext, this.root), footerImageDetails(templateContext, this.root)])\n .then(() => {\n this.stopImageLoading();\n return;\n })\n .then(() => {\n const imagedetails = new ImageDetails(\n this.root,\n this.editor,\n this.currentModal,\n this.canShowFilePicker,\n this.canShowDropZone,\n url,\n image,\n );\n imagedetails.init();\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n });\n };\n\n getSelectedImageProperties() {\n const image = this.getSelectedImage();\n if (!image) {\n this.selectedImage = null;\n return null;\n }\n\n const properties = {\n src: null,\n alt: null,\n width: null,\n height: null,\n presentation: false,\n customStyle: '', // Custom CSS styles applied to the image.\n };\n\n const getImageHeight = (image) => {\n if (!isPercentageValue(String(image.height))) {\n return parseInt(image.height, 10);\n }\n\n return image.height;\n };\n\n const getImageWidth = (image) => {\n if (!isPercentageValue(String(image.width))) {\n return parseInt(image.width, 10);\n }\n\n return image.width;\n };\n\n // Get the current selection.\n this.selectedImage = image;\n\n properties.customStyle = image.style.cssText;\n\n const width = getImageWidth(image);\n if (width !== 0) {\n properties.width = width;\n }\n\n const height = getImageHeight(image);\n if (height !== 0) {\n properties.height = height;\n }\n\n properties.src = image.getAttribute('src');\n properties.alt = image.getAttribute('alt') || '';\n properties.presentation = (image.getAttribute('role') === 'presentation');\n\n return properties;\n }\n\n getSelectedImage() {\n const imgElm = this.editor.selection.getNode();\n const figureElm = this.editor.dom.getParent(imgElm, 'figure.image');\n if (figureElm) {\n return this.editor.dom.select('img', figureElm)[0];\n }\n\n if (imgElm && (imgElm.nodeName.toUpperCase() !== 'IMG' || this.isPlaceholderImage(imgElm))) {\n return null;\n }\n return imgElm;\n }\n\n isPlaceholderImage(imgElm) {\n if (imgElm.nodeName.toUpperCase() !== 'IMG') {\n return false;\n }\n\n return (imgElm.hasAttribute('data-mce-object') || imgElm.hasAttribute('data-mce-placeholder'));\n }\n\n /**\n * Displays the upload loader and disables UI elements while loading a file.\n */\n startImageLoading() {\n showElements(Selectors.IMAGE.elements.loaderIcon, this.root);\n hideElements(Selectors.IMAGE.elements.insertImage, this.root);\n }\n\n /**\n * Displays the upload loader and disables UI elements while loading a file.\n */\n stopImageLoading() {\n hideElements(Selectors.IMAGE.elements.loaderIcon, this.root);\n showElements(Selectors.IMAGE.elements.insertImage, this.root);\n }\n}\n"],"names":["constructor","editor","async","templateContext","elementid","this","id","showfilepicker","canShowFilePicker","showdropzone","canShowDropZone","Promise","all","root","then","ImageInsert","currentModal","init","catch","error","window","console","log","url","startImageLoading","image","Image","src","addEventListener","querySelector","Selectors","IMAGE","elements","urlWarning","innerHTML","stopImageLoading","currentImageData","getCurrentImageData","getTemplateContext","sizecustomhelpicon","text","ImageDetails","permissions","options","filepicker","Object","keys","repositories","length","values","some","repository","type","ImageModal","create","getRoot","loadPreviewImage","loadInsertImage","data","selectedImageProperties","getSelectedImageProperties","properties","haspreview","alt","presentation","getSelectedImage","selectedImage","width","height","customStyle","style","cssText","String","parseInt","getImageWidth","getImageHeight","getAttribute","imgElm","selection","getNode","figureElm","dom","getParent","select","nodeName","toUpperCase","isPlaceholderImage","hasAttribute","loaderIcon","insertImage"],"mappings":"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"} \ No newline at end of file diff --git a/lib/editor/tiny/plugins/media/amd/src/image.js b/lib/editor/tiny/plugins/media/amd/src/image.js index 7ca5d14ae63af..514dd25b06f4c 100644 --- a/lib/editor/tiny/plugins/media/amd/src/image.js +++ b/lib/editor/tiny/plugins/media/amd/src/image.js @@ -27,6 +27,7 @@ import {getImagePermissions} from './options'; import {getFilePicker} from 'editor_tiny/options'; import {ImageInsert} from 'tiny_media/imageinsert'; import {ImageDetails} from 'tiny_media/imagedetails'; +import {prefetchStrings} from 'core/prefetch'; import {getString} from 'core/str'; import { bodyImageInsert, @@ -38,6 +39,11 @@ import { isPercentageValue, } from 'tiny_media/imagehelpers'; +prefetchStrings('tiny_media', [ + 'imageurlrequired', + 'sizecustom_help', +]); + export default class MediaImage { canShowFilePicker = false; editor = null; @@ -138,9 +144,9 @@ export default class MediaImage { this.startImageLoading(); const image = new Image(); image.src = url; - image.addEventListener('error', () => { + image.addEventListener('error', async() => { const urlWarningLabelEle = this.root.querySelector(Selectors.IMAGE.elements.urlWarning); - urlWarningLabelEle.innerHTML = this.langStrings.imageurlrequired; + urlWarningLabelEle.innerHTML = await getString('imageurlrequired', 'tiny_media'); showElements(Selectors.IMAGE.elements.urlWarning, this.root); this.stopImageLoading(); });