From ffcd39af1f91b0cda66441d79b727bf5705d1eab Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Tue, 5 Nov 2024 07:05:52 +0000 Subject: [PATCH] MDL-83579 tiny_media: pass filepicker accepted types to dropzone. --- .../tiny/plugins/media/amd/build/imageinsert.min.js | 2 +- .../plugins/media/amd/build/imageinsert.min.js.map | 2 +- lib/editor/tiny/plugins/media/amd/src/imageinsert.js | 10 +++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/editor/tiny/plugins/media/amd/build/imageinsert.min.js b/lib/editor/tiny/plugins/media/amd/build/imageinsert.min.js index 0a825a9a150..11e4cf975cc 100644 --- a/lib/editor/tiny/plugins/media/amd/build/imageinsert.min.js +++ b/lib/editor/tiny/plugins/media/amd/build/imageinsert.min.js @@ -1,3 +1,3 @@ -define("tiny_media/imageinsert",["exports","./selectors","core/dropzone","editor_tiny/uploader","core/prefetch","core/str","./common","editor_tiny/utils","tiny_media/imagedetails","tiny_media/imagehelpers"],(function(_exports,_selectors,_dropzone,_uploader,_prefetch,_str,_common,_utils,_imagedetails,_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.ImageInsert=void 0,_selectors=_interopRequireDefault(_selectors),_dropzone=_interopRequireDefault(_dropzone),_uploader=_interopRequireDefault(_uploader),(0,_prefetch.prefetchStrings)("tiny_media",["insertimage","enterurl","enterurlor","imageurlrequired","uploading","loading","addfilesdrop","sizecustom_help"]);_exports.ImageInsert=class{constructor(_root,editor,currentModal,canShowFilePicker,canShowDropZone){_defineProperty(this,"init",(async function(){const langStringKeys=["insertimage","enterurl","enterurlor","imageurlrequired","uploading","loading","addfilesdrop","sizecustom_help"],langStringvalues=await(0,_str.getStrings)([...langStringKeys].map((key=>({key:key,component:_common.component}))));if(this.langStrings=Object.fromEntries(langStringKeys.map(((key,index)=>[key,langStringvalues[index]]))),this.currentModal.setTitle(this.langStrings.insertimage),this.canShowDropZone){const dropZoneEle=document.querySelector(_selectors.default.IMAGE.elements.dropzoneContainer),dropZone=new _dropzone.default(dropZoneEle,"image/*",(files=>{this.handleUploadedFile(files)}));dropZone.setLabel(this.langStrings.addfilesdrop),dropZone.init()}await this.registerEventListeners()})),_defineProperty(this,"isValidUrl",(urlString=>!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3})|localhost)(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*").test(urlString))),_defineProperty(this,"loadPreviewImage",(function(url){this.startImageLoading(),this.currentUrl=url;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.currentUrl="",this.stopImageLoading()})),image.addEventListener("load",(()=>{let templateContext={};templateContext.sizecustomhelpicon={text:this.langStrings.sizecustom_help},templateContext.maxlengthalt=_imagehelpers.MAX_LENGTH_ALT,Promise.all([(0,_imagehelpers.bodyImageDetails)(templateContext,this.root),(0,_imagehelpers.footerImageDetails)(templateContext,this.root)]).then((()=>{new _imagedetails.ImageDetails(this.root,this.editor,this.currentModal,this.canShowFilePicker,this.canShowDropZone,this.currentUrl,image).init()})).then((()=>{this.stopImageLoading()})).catch((error=>{window.console.log(error)}))}))})),_defineProperty(this,"updateLoaderIcon",(function(root,langStrings){let progress=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const loaderIcon=root.querySelector(_selectors.default.IMAGE.elements.loaderIconContainer+" div");loaderIcon.innerHTML=null!==progress?"".concat(langStrings.uploading," ").concat(Math.round(progress),"%"):langStrings.loading})),_defineProperty(this,"handleUploadedFile",(async files=>{try{this.startImageLoading();const fileURL=await(0,_uploader.default)(this.editor,"image",files[0],files[0].name,(progress=>{this.updateLoaderIcon(this.root,this.langStrings,progress)}));this.updateLoaderIcon(this.root,this.langStrings),this.filePickerCallback({url:fileURL})}catch(error){this.root.querySelector(_selectors.default.IMAGE.elements.urlWarning).innerHTML=void 0!==error.error?error.error:error,(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.urlWarning,this.root),this.stopImageLoading()}})),this.root=_root,this.editor=editor,this.currentModal=currentModal,this.canShowFilePicker=canShowFilePicker,this.canShowDropZone=canShowDropZone}toggleUrlButton(){const url=this.root.querySelector(_selectors.default.IMAGE.elements.url).value;this.root.querySelector(_selectors.default.IMAGE.actions.addUrl).disabled=!(""!==url&&this.isValidUrl(url))}urlChanged(){(0,_imagehelpers.hideElements)(_selectors.default.IMAGE.elements.urlWarning,this.root);const input=this.root.querySelector(_selectors.default.IMAGE.elements.url);input.value&&input.value!==this.currentUrl&&this.loadPreviewImage(input.value)}startImageLoading(){(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.loaderIcon,this.root);const elementsToHide=[_selectors.default.IMAGE.elements.insertImage,_selectors.default.IMAGE.elements.urlWarning,_selectors.default.IMAGE.elements.modalFooter];(0,_imagehelpers.hideElements)(elementsToHide,this.root)}stopImageLoading(){(0,_imagehelpers.hideElements)(_selectors.default.IMAGE.elements.loaderIcon,this.root);const elementsToShow=[_selectors.default.IMAGE.elements.insertImage,_selectors.default.IMAGE.elements.modalFooter];(0,_imagehelpers.showElements)(elementsToShow,this.root)}filePickerCallback(params){params.url&&this.loadPreviewImage(params.url)}registerEventListeners(){this.root.addEventListener("click",(async e=>{e.target.closest(_selectors.default.IMAGE.actions.addUrl)&&this.urlChanged();if(e.target.closest(_selectors.default.IMAGE.actions.imageBrowser)&&this.canShowFilePicker){e.preventDefault();const params=await(0,_utils.displayFilepicker)(this.editor,"image");this.filePickerCallback(params)}})),this.root.addEventListener("input",(e=>{e.target.closest(_selectors.default.IMAGE.elements.url)&&this.toggleUrlButton()}));const fileInput=this.root.querySelector(_selectors.default.IMAGE.elements.fileInput);fileInput&&fileInput.addEventListener("change",(()=>{this.handleUploadedFile(fileInput.files)}))}}})); +define("tiny_media/imageinsert",["exports","./selectors","core/dropzone","editor_tiny/uploader","core/prefetch","core/str","./common","editor_tiny/options","editor_tiny/utils","tiny_media/imagedetails","tiny_media/imagehelpers"],(function(_exports,_selectors,_dropzone,_uploader,_prefetch,_str,_common,_options,_utils,_imagedetails,_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.ImageInsert=void 0,_selectors=_interopRequireDefault(_selectors),_dropzone=_interopRequireDefault(_dropzone),_uploader=_interopRequireDefault(_uploader),(0,_prefetch.prefetchStrings)("tiny_media",["insertimage","enterurl","enterurlor","imageurlrequired","uploading","loading","addfilesdrop","sizecustom_help"]);_exports.ImageInsert=class{constructor(_root,editor,currentModal,canShowFilePicker,canShowDropZone){_defineProperty(this,"init",(async function(){const langStringKeys=["insertimage","enterurl","enterurlor","imageurlrequired","uploading","loading","addfilesdrop","sizecustom_help"],langStringvalues=await(0,_str.getStrings)([...langStringKeys].map((key=>({key:key,component:_common.component}))));if(this.langStrings=Object.fromEntries(langStringKeys.map(((key,index)=>[key,langStringvalues[index]]))),this.currentModal.setTitle(this.langStrings.insertimage),this.canShowDropZone){const dropZoneEle=document.querySelector(_selectors.default.IMAGE.elements.dropzoneContainer);let acceptedTypes=(0,_options.getFilePicker)(this.editor,"image").accepted_types;Array.isArray(acceptedTypes)&&(acceptedTypes=acceptedTypes.join(","));const dropZone=new _dropzone.default(dropZoneEle,acceptedTypes,(files=>{this.handleUploadedFile(files)}));dropZone.setLabel(this.langStrings.addfilesdrop),dropZone.init()}await this.registerEventListeners()})),_defineProperty(this,"isValidUrl",(urlString=>!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3})|localhost)(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*").test(urlString))),_defineProperty(this,"loadPreviewImage",(function(url){this.startImageLoading(),this.currentUrl=url;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.currentUrl="",this.stopImageLoading()})),image.addEventListener("load",(()=>{let templateContext={};templateContext.sizecustomhelpicon={text:this.langStrings.sizecustom_help},templateContext.maxlengthalt=_imagehelpers.MAX_LENGTH_ALT,Promise.all([(0,_imagehelpers.bodyImageDetails)(templateContext,this.root),(0,_imagehelpers.footerImageDetails)(templateContext,this.root)]).then((()=>{new _imagedetails.ImageDetails(this.root,this.editor,this.currentModal,this.canShowFilePicker,this.canShowDropZone,this.currentUrl,image).init()})).then((()=>{this.stopImageLoading()})).catch((error=>{window.console.log(error)}))}))})),_defineProperty(this,"updateLoaderIcon",(function(root,langStrings){let progress=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;const loaderIcon=root.querySelector(_selectors.default.IMAGE.elements.loaderIconContainer+" div");loaderIcon.innerHTML=null!==progress?"".concat(langStrings.uploading," ").concat(Math.round(progress),"%"):langStrings.loading})),_defineProperty(this,"handleUploadedFile",(async files=>{try{this.startImageLoading();const fileURL=await(0,_uploader.default)(this.editor,"image",files[0],files[0].name,(progress=>{this.updateLoaderIcon(this.root,this.langStrings,progress)}));this.updateLoaderIcon(this.root,this.langStrings),this.filePickerCallback({url:fileURL})}catch(error){this.root.querySelector(_selectors.default.IMAGE.elements.urlWarning).innerHTML=void 0!==error.error?error.error:error,(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.urlWarning,this.root),this.stopImageLoading()}})),this.root=_root,this.editor=editor,this.currentModal=currentModal,this.canShowFilePicker=canShowFilePicker,this.canShowDropZone=canShowDropZone}toggleUrlButton(){const url=this.root.querySelector(_selectors.default.IMAGE.elements.url).value;this.root.querySelector(_selectors.default.IMAGE.actions.addUrl).disabled=!(""!==url&&this.isValidUrl(url))}urlChanged(){(0,_imagehelpers.hideElements)(_selectors.default.IMAGE.elements.urlWarning,this.root);const input=this.root.querySelector(_selectors.default.IMAGE.elements.url);input.value&&input.value!==this.currentUrl&&this.loadPreviewImage(input.value)}startImageLoading(){(0,_imagehelpers.showElements)(_selectors.default.IMAGE.elements.loaderIcon,this.root);const elementsToHide=[_selectors.default.IMAGE.elements.insertImage,_selectors.default.IMAGE.elements.urlWarning,_selectors.default.IMAGE.elements.modalFooter];(0,_imagehelpers.hideElements)(elementsToHide,this.root)}stopImageLoading(){(0,_imagehelpers.hideElements)(_selectors.default.IMAGE.elements.loaderIcon,this.root);const elementsToShow=[_selectors.default.IMAGE.elements.insertImage,_selectors.default.IMAGE.elements.modalFooter];(0,_imagehelpers.showElements)(elementsToShow,this.root)}filePickerCallback(params){params.url&&this.loadPreviewImage(params.url)}registerEventListeners(){this.root.addEventListener("click",(async e=>{e.target.closest(_selectors.default.IMAGE.actions.addUrl)&&this.urlChanged();if(e.target.closest(_selectors.default.IMAGE.actions.imageBrowser)&&this.canShowFilePicker){e.preventDefault();const params=await(0,_utils.displayFilepicker)(this.editor,"image");this.filePickerCallback(params)}})),this.root.addEventListener("input",(e=>{e.target.closest(_selectors.default.IMAGE.elements.url)&&this.toggleUrlButton()}));const fileInput=this.root.querySelector(_selectors.default.IMAGE.elements.fileInput);fileInput&&fileInput.addEventListener("change",(()=>{this.handleUploadedFile(fileInput.files)}))}}})); //# sourceMappingURL=imageinsert.min.js.map \ No newline at end of file diff --git a/lib/editor/tiny/plugins/media/amd/build/imageinsert.min.js.map b/lib/editor/tiny/plugins/media/amd/build/imageinsert.min.js.map index 9cf720649a2..60174049073 100644 --- a/lib/editor/tiny/plugins/media/amd/build/imageinsert.min.js.map +++ b/lib/editor/tiny/plugins/media/amd/build/imageinsert.min.js.map @@ -1 +1 @@ -{"version":3,"file":"imageinsert.min.js","sources":["../src/imageinsert.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 insertion class for Moodle.\n *\n * @module tiny_media/imageinsert\n * @copyright 2024 Meirza \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from './selectors';\nimport Dropzone from 'core/dropzone';\nimport uploadFile from 'editor_tiny/uploader';\nimport {prefetchStrings} from 'core/prefetch';\nimport {getStrings} from 'core/str';\nimport {component} from \"./common\";\nimport {displayFilepicker} from 'editor_tiny/utils';\nimport {ImageDetails} from 'tiny_media/imagedetails';\nimport {\n showElements,\n hideElements,\n bodyImageDetails,\n footerImageDetails,\n MAX_LENGTH_ALT,\n} from 'tiny_media/imagehelpers';\n\nprefetchStrings('tiny_media', [\n 'insertimage',\n 'enterurl',\n 'enterurlor',\n 'imageurlrequired',\n 'uploading',\n 'loading',\n 'addfilesdrop',\n 'sizecustom_help',\n]);\n\nexport class ImageInsert {\n\n constructor(\n root,\n editor,\n currentModal,\n canShowFilePicker,\n canShowDropZone,\n ) {\n this.root = root;\n this.editor = editor;\n this.currentModal = currentModal;\n this.canShowFilePicker = canShowFilePicker;\n this.canShowDropZone = canShowDropZone;\n }\n\n init = async function() {\n // Get the localization lang strings and turn them into object.\n const langStringKeys = [\n 'insertimage',\n 'enterurl',\n 'enterurlor',\n 'imageurlrequired',\n 'uploading',\n 'loading',\n 'addfilesdrop',\n 'sizecustom_help',\n ];\n const langStringvalues = await getStrings([...langStringKeys].map((key) => ({key, component})));\n\n // Convert array to object.\n this.langStrings = Object.fromEntries(langStringKeys.map((key, index) => [key, langStringvalues[index]]));\n this.currentModal.setTitle(this.langStrings.insertimage);\n if (this.canShowDropZone) {\n const dropZoneEle = document.querySelector(Selectors.IMAGE.elements.dropzoneContainer);\n const dropZone = new Dropzone(\n dropZoneEle,\n 'image/*',\n files => {\n this.handleUploadedFile(files);\n }\n );\n dropZone.setLabel(this.langStrings.addfilesdrop);\n dropZone.init();\n }\n await this.registerEventListeners();\n };\n\n /**\n * Enables or disables the URL-related buttons in the footer based on the current URL and input value.\n */\n toggleUrlButton() {\n const urlInput = this.root.querySelector(Selectors.IMAGE.elements.url);\n const url = urlInput.value;\n const addUrl = this.root.querySelector(Selectors.IMAGE.actions.addUrl);\n addUrl.disabled = !(url !== \"\" && this.isValidUrl(url));\n }\n\n /**\n * Check if given string is a valid URL.\n *\n * @param {String} urlString URL the link will point to.\n * @returns {boolean} True is valid, otherwise false.\n */\n isValidUrl = urlString => {\n const urlPattern = new RegExp('^(https?:\\\\/\\\\/)?' + // Protocol.\n '((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|' + // Domain name.\n '((\\\\d{1,3}\\\\.){3}\\\\d{1,3})|localhost)' + // OR ip (v4) address, localhost.\n '(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*'); // Port and path.\n return !!urlPattern.test(urlString);\n };\n\n /**\n * Handles changes in the image URL input field and loads a preview of the image if the URL has changed.\n */\n urlChanged() {\n hideElements(Selectors.IMAGE.elements.urlWarning, this.root);\n const input = this.root.querySelector(Selectors.IMAGE.elements.url);\n if (input.value && input.value !== this.currentUrl) {\n this.loadPreviewImage(input.value);\n }\n }\n\n /**\n * Loads and displays a preview image based on the provided URL, and handles image loading events.\n *\n * @param {string} url - The URL of the image to load and display.\n */\n loadPreviewImage = function(url) {\n this.startImageLoading();\n this.currentUrl = url;\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.currentUrl = \"\";\n this.stopImageLoading();\n });\n\n image.addEventListener('load', () => {\n let templateContext = {};\n templateContext.sizecustomhelpicon = {text: this.langStrings.sizecustom_help};\n templateContext.maxlengthalt = MAX_LENGTH_ALT;\n Promise.all([bodyImageDetails(templateContext, this.root), footerImageDetails(templateContext, this.root)])\n .then(() => {\n const imagedetails = new ImageDetails(\n this.root,\n this.editor,\n this.currentModal,\n this.canShowFilePicker,\n this.canShowDropZone,\n this.currentUrl,\n image,\n );\n imagedetails.init();\n return;\n }).then(() => {\n this.stopImageLoading();\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n });\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 const elementsToHide = [\n Selectors.IMAGE.elements.insertImage,\n Selectors.IMAGE.elements.urlWarning,\n Selectors.IMAGE.elements.modalFooter,\n ];\n hideElements(elementsToHide, 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 const elementsToShow = [\n Selectors.IMAGE.elements.insertImage,\n Selectors.IMAGE.elements.modalFooter,\n ];\n showElements(elementsToShow, this.root);\n }\n\n filePickerCallback(params) {\n if (params.url) {\n this.loadPreviewImage(params.url);\n }\n }\n\n /**\n * Updates the content of the loader icon.\n *\n * @param {HTMLElement} root - The root element containing the loader icon.\n * @param {object} langStrings - An object containing language strings.\n * @param {number|null} progress - The progress percentage (optional).\n * @returns {void}\n */\n updateLoaderIcon = (root, langStrings, progress = null) => {\n const loaderIcon = root.querySelector(Selectors.IMAGE.elements.loaderIconContainer + ' div');\n loaderIcon.innerHTML = progress !== null ? `${langStrings.uploading} ${Math.round(progress)}%` : langStrings.loading;\n };\n\n /**\n * Handles the uploaded file, initiates the upload process, and updates the UI during the upload.\n *\n * @param {FileList} files - The list of files to upload (usually from a file input field).\n * @returns {Promise} A promise that resolves when the file is uploaded and processed.\n */\n handleUploadedFile = async(files) => {\n try {\n this.startImageLoading();\n const fileURL = await uploadFile(this.editor, 'image', files[0], files[0].name, (progress) => {\n this.updateLoaderIcon(this.root, this.langStrings, progress);\n });\n // Set the loader icon content to \"loading\" after the file upload completes.\n this.updateLoaderIcon(this.root, this.langStrings);\n this.filePickerCallback({url: fileURL});\n } catch (error) {\n // Handle the error.\n const urlWarningLabelEle = this.root.querySelector(Selectors.IMAGE.elements.urlWarning);\n urlWarningLabelEle.innerHTML = error.error !== undefined ? error.error : error;\n showElements(Selectors.IMAGE.elements.urlWarning, this.root);\n this.stopImageLoading();\n }\n };\n\n registerEventListeners() {\n this.root.addEventListener('click', async(e) => {\n const addUrlEle = e.target.closest(Selectors.IMAGE.actions.addUrl);\n if (addUrlEle) {\n this.urlChanged();\n }\n\n const imageBrowserAction = e.target.closest(Selectors.IMAGE.actions.imageBrowser);\n if (imageBrowserAction && this.canShowFilePicker) {\n e.preventDefault();\n const params = await displayFilepicker(this.editor, 'image');\n this.filePickerCallback(params);\n }\n });\n\n this.root.addEventListener('input', (e) => {\n const urlEle = e.target.closest(Selectors.IMAGE.elements.url);\n if (urlEle) {\n this.toggleUrlButton();\n }\n });\n\n const fileInput = this.root.querySelector(Selectors.IMAGE.elements.fileInput);\n if (fileInput) {\n fileInput.addEventListener('change', () => {\n this.handleUploadedFile(fileInput.files);\n });\n }\n }\n}"],"names":["constructor","root","editor","currentModal","canShowFilePicker","canShowDropZone","async","langStringKeys","langStringvalues","map","key","component","langStrings","Object","fromEntries","index","setTitle","this","insertimage","dropZoneEle","document","querySelector","Selectors","IMAGE","elements","dropzoneContainer","dropZone","Dropzone","files","handleUploadedFile","setLabel","addfilesdrop","init","registerEventListeners","urlString","RegExp","test","url","startImageLoading","currentUrl","image","Image","src","addEventListener","urlWarning","innerHTML","imageurlrequired","stopImageLoading","templateContext","sizecustomhelpicon","text","sizecustom_help","maxlengthalt","MAX_LENGTH_ALT","Promise","all","then","ImageDetails","catch","error","window","console","log","progress","loaderIcon","loaderIconContainer","uploading","Math","round","loading","fileURL","name","updateLoaderIcon","filePickerCallback","undefined","toggleUrlButton","value","actions","addUrl","disabled","isValidUrl","urlChanged","input","loadPreviewImage","elementsToHide","insertImage","modalFooter","elementsToShow","params","e","target","closest","imageBrowser","preventDefault","fileInput"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"imageinsert.min.js","sources":["../src/imageinsert.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 insertion class for Moodle.\n *\n * @module tiny_media/imageinsert\n * @copyright 2024 Meirza \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Selectors from './selectors';\nimport Dropzone from 'core/dropzone';\nimport uploadFile from 'editor_tiny/uploader';\nimport {prefetchStrings} from 'core/prefetch';\nimport {getStrings} from 'core/str';\nimport {component} from \"./common\";\nimport {getFilePicker} from 'editor_tiny/options';\nimport {displayFilepicker} from 'editor_tiny/utils';\nimport {ImageDetails} from 'tiny_media/imagedetails';\nimport {\n showElements,\n hideElements,\n bodyImageDetails,\n footerImageDetails,\n MAX_LENGTH_ALT,\n} from 'tiny_media/imagehelpers';\n\nprefetchStrings('tiny_media', [\n 'insertimage',\n 'enterurl',\n 'enterurlor',\n 'imageurlrequired',\n 'uploading',\n 'loading',\n 'addfilesdrop',\n 'sizecustom_help',\n]);\n\nexport class ImageInsert {\n\n constructor(\n root,\n editor,\n currentModal,\n canShowFilePicker,\n canShowDropZone,\n ) {\n this.root = root;\n this.editor = editor;\n this.currentModal = currentModal;\n this.canShowFilePicker = canShowFilePicker;\n this.canShowDropZone = canShowDropZone;\n }\n\n init = async function() {\n // Get the localization lang strings and turn them into object.\n const langStringKeys = [\n 'insertimage',\n 'enterurl',\n 'enterurlor',\n 'imageurlrequired',\n 'uploading',\n 'loading',\n 'addfilesdrop',\n 'sizecustom_help',\n ];\n const langStringvalues = await getStrings([...langStringKeys].map((key) => ({key, component})));\n\n // Convert array to object.\n this.langStrings = Object.fromEntries(langStringKeys.map((key, index) => [key, langStringvalues[index]]));\n this.currentModal.setTitle(this.langStrings.insertimage);\n if (this.canShowDropZone) {\n const dropZoneEle = document.querySelector(Selectors.IMAGE.elements.dropzoneContainer);\n\n // Accepted types can be either a string or an array.\n let acceptedTypes = getFilePicker(this.editor, 'image').accepted_types;\n if (Array.isArray(acceptedTypes)) {\n acceptedTypes = acceptedTypes.join(',');\n }\n\n const dropZone = new Dropzone(\n dropZoneEle,\n acceptedTypes,\n files => {\n this.handleUploadedFile(files);\n }\n );\n dropZone.setLabel(this.langStrings.addfilesdrop);\n dropZone.init();\n }\n await this.registerEventListeners();\n };\n\n /**\n * Enables or disables the URL-related buttons in the footer based on the current URL and input value.\n */\n toggleUrlButton() {\n const urlInput = this.root.querySelector(Selectors.IMAGE.elements.url);\n const url = urlInput.value;\n const addUrl = this.root.querySelector(Selectors.IMAGE.actions.addUrl);\n addUrl.disabled = !(url !== \"\" && this.isValidUrl(url));\n }\n\n /**\n * Check if given string is a valid URL.\n *\n * @param {String} urlString URL the link will point to.\n * @returns {boolean} True is valid, otherwise false.\n */\n isValidUrl = urlString => {\n const urlPattern = new RegExp('^(https?:\\\\/\\\\/)?' + // Protocol.\n '((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|' + // Domain name.\n '((\\\\d{1,3}\\\\.){3}\\\\d{1,3})|localhost)' + // OR ip (v4) address, localhost.\n '(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*'); // Port and path.\n return !!urlPattern.test(urlString);\n };\n\n /**\n * Handles changes in the image URL input field and loads a preview of the image if the URL has changed.\n */\n urlChanged() {\n hideElements(Selectors.IMAGE.elements.urlWarning, this.root);\n const input = this.root.querySelector(Selectors.IMAGE.elements.url);\n if (input.value && input.value !== this.currentUrl) {\n this.loadPreviewImage(input.value);\n }\n }\n\n /**\n * Loads and displays a preview image based on the provided URL, and handles image loading events.\n *\n * @param {string} url - The URL of the image to load and display.\n */\n loadPreviewImage = function(url) {\n this.startImageLoading();\n this.currentUrl = url;\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.currentUrl = \"\";\n this.stopImageLoading();\n });\n\n image.addEventListener('load', () => {\n let templateContext = {};\n templateContext.sizecustomhelpicon = {text: this.langStrings.sizecustom_help};\n templateContext.maxlengthalt = MAX_LENGTH_ALT;\n Promise.all([bodyImageDetails(templateContext, this.root), footerImageDetails(templateContext, this.root)])\n .then(() => {\n const imagedetails = new ImageDetails(\n this.root,\n this.editor,\n this.currentModal,\n this.canShowFilePicker,\n this.canShowDropZone,\n this.currentUrl,\n image,\n );\n imagedetails.init();\n return;\n }).then(() => {\n this.stopImageLoading();\n return;\n })\n .catch(error => {\n window.console.log(error);\n });\n });\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 const elementsToHide = [\n Selectors.IMAGE.elements.insertImage,\n Selectors.IMAGE.elements.urlWarning,\n Selectors.IMAGE.elements.modalFooter,\n ];\n hideElements(elementsToHide, 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 const elementsToShow = [\n Selectors.IMAGE.elements.insertImage,\n Selectors.IMAGE.elements.modalFooter,\n ];\n showElements(elementsToShow, this.root);\n }\n\n filePickerCallback(params) {\n if (params.url) {\n this.loadPreviewImage(params.url);\n }\n }\n\n /**\n * Updates the content of the loader icon.\n *\n * @param {HTMLElement} root - The root element containing the loader icon.\n * @param {object} langStrings - An object containing language strings.\n * @param {number|null} progress - The progress percentage (optional).\n * @returns {void}\n */\n updateLoaderIcon = (root, langStrings, progress = null) => {\n const loaderIcon = root.querySelector(Selectors.IMAGE.elements.loaderIconContainer + ' div');\n loaderIcon.innerHTML = progress !== null ? `${langStrings.uploading} ${Math.round(progress)}%` : langStrings.loading;\n };\n\n /**\n * Handles the uploaded file, initiates the upload process, and updates the UI during the upload.\n *\n * @param {FileList} files - The list of files to upload (usually from a file input field).\n * @returns {Promise} A promise that resolves when the file is uploaded and processed.\n */\n handleUploadedFile = async(files) => {\n try {\n this.startImageLoading();\n const fileURL = await uploadFile(this.editor, 'image', files[0], files[0].name, (progress) => {\n this.updateLoaderIcon(this.root, this.langStrings, progress);\n });\n // Set the loader icon content to \"loading\" after the file upload completes.\n this.updateLoaderIcon(this.root, this.langStrings);\n this.filePickerCallback({url: fileURL});\n } catch (error) {\n // Handle the error.\n const urlWarningLabelEle = this.root.querySelector(Selectors.IMAGE.elements.urlWarning);\n urlWarningLabelEle.innerHTML = error.error !== undefined ? error.error : error;\n showElements(Selectors.IMAGE.elements.urlWarning, this.root);\n this.stopImageLoading();\n }\n };\n\n registerEventListeners() {\n this.root.addEventListener('click', async(e) => {\n const addUrlEle = e.target.closest(Selectors.IMAGE.actions.addUrl);\n if (addUrlEle) {\n this.urlChanged();\n }\n\n const imageBrowserAction = e.target.closest(Selectors.IMAGE.actions.imageBrowser);\n if (imageBrowserAction && this.canShowFilePicker) {\n e.preventDefault();\n const params = await displayFilepicker(this.editor, 'image');\n this.filePickerCallback(params);\n }\n });\n\n this.root.addEventListener('input', (e) => {\n const urlEle = e.target.closest(Selectors.IMAGE.elements.url);\n if (urlEle) {\n this.toggleUrlButton();\n }\n });\n\n const fileInput = this.root.querySelector(Selectors.IMAGE.elements.fileInput);\n if (fileInput) {\n fileInput.addEventListener('change', () => {\n this.handleUploadedFile(fileInput.files);\n });\n }\n }\n}"],"names":["constructor","root","editor","currentModal","canShowFilePicker","canShowDropZone","async","langStringKeys","langStringvalues","map","key","component","langStrings","Object","fromEntries","index","setTitle","this","insertimage","dropZoneEle","document","querySelector","Selectors","IMAGE","elements","dropzoneContainer","acceptedTypes","accepted_types","Array","isArray","join","dropZone","Dropzone","files","handleUploadedFile","setLabel","addfilesdrop","init","registerEventListeners","urlString","RegExp","test","url","startImageLoading","currentUrl","image","Image","src","addEventListener","urlWarning","innerHTML","imageurlrequired","stopImageLoading","templateContext","sizecustomhelpicon","text","sizecustom_help","maxlengthalt","MAX_LENGTH_ALT","Promise","all","then","ImageDetails","catch","error","window","console","log","progress","loaderIcon","loaderIconContainer","uploading","Math","round","loading","fileURL","name","updateLoaderIcon","filePickerCallback","undefined","toggleUrlButton","value","actions","addUrl","disabled","isValidUrl","urlChanged","input","loadPreviewImage","elementsToHide","insertImage","modalFooter","elementsToShow","params","e","target","closest","imageBrowser","preventDefault","fileInput"],"mappings":"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"} \ No newline at end of file diff --git a/lib/editor/tiny/plugins/media/amd/src/imageinsert.js b/lib/editor/tiny/plugins/media/amd/src/imageinsert.js index 5bb7ab46873..272a6944752 100644 --- a/lib/editor/tiny/plugins/media/amd/src/imageinsert.js +++ b/lib/editor/tiny/plugins/media/amd/src/imageinsert.js @@ -27,6 +27,7 @@ import uploadFile from 'editor_tiny/uploader'; import {prefetchStrings} from 'core/prefetch'; import {getStrings} from 'core/str'; import {component} from "./common"; +import {getFilePicker} from 'editor_tiny/options'; import {displayFilepicker} from 'editor_tiny/utils'; import {ImageDetails} from 'tiny_media/imagedetails'; import { @@ -83,9 +84,16 @@ export class ImageInsert { this.currentModal.setTitle(this.langStrings.insertimage); if (this.canShowDropZone) { const dropZoneEle = document.querySelector(Selectors.IMAGE.elements.dropzoneContainer); + + // Accepted types can be either a string or an array. + let acceptedTypes = getFilePicker(this.editor, 'image').accepted_types; + if (Array.isArray(acceptedTypes)) { + acceptedTypes = acceptedTypes.join(','); + } + const dropZone = new Dropzone( dropZoneEle, - 'image/*', + acceptedTypes, files => { this.handleUploadedFile(files); }