diff --git a/amd/build/controllers/file.min.js b/amd/build/controllers/file.min.js
index 69cfa78..7d48f44 100644
--- a/amd/build/controllers/file.min.js
+++ b/amd/build/controllers/file.min.js
@@ -1,3 +1,3 @@
-define("tiny_ai/controllers/file",["exports","tiny_ai/utils","core/templates","tiny_ai/selectors","tiny_ai/datahandler/basedata","core/str"],(function(_exports,_utils,_templates,_selectors,BasedataHandler,_str){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=_interopRequireDefault(_templates),_selectors=_interopRequireDefault(_selectors),BasedataHandler=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}(BasedataHandler);return _exports.default=class{constructor(baseSelector){_defineProperty(this,"dropzone",null),_defineProperty(this,"dropzoneContentToResetTo",""),this.baseElement=document.querySelector(baseSelector)}async init(){this.dropzone=this.baseElement.querySelector('[data-type="dropzone"]');const dropzone=this.dropzone;dropzone.contentEditable=!0,this.setDropzoneContent(dropzone.innerHTML),dropzone.focus();const _this=this;dropzone.addEventListener("input",(()=>{dropzone.innerHTML!==_this.dropzoneContentToResetTo&&(dropzone.innerHTML=_this.dropzoneContentToResetTo)})),dropzone.addEventListener("drop",(async event=>{if(event.preventDefault(),event.dataTransfer.items){const item=[...event.dataTransfer.items].shift();"file"===item.kind&&await this.handleFile(item.getAsFile())}else await this.handleFile([...event.dataTransfer.files].shift())})),document.querySelector(_selectors.default.modalDialog).addEventListener("paste",(async event=>{event.preventDefault();const clipboardData=event.clipboardData||window.clipboardData;if(0===clipboardData.files.length)return void await(0,_utils.errorAlert)(BasedataHandler.getTinyAiString("error_nofileinclipboard_text"),BasedataHandler.getTinyAiString("error_nofileinclipboard_title"));const file=clipboardData.files[0];this.handleFile(file)})),dropzone.addEventListener("dragover",(event=>{event.preventDefault(),dropzone.classList.remove("tiny_ai_dropzone_filled"),dropzone.classList.add("tiny_ai_dragover")})),dropzone.addEventListener("dragleave",(event=>{event.preventDefault(),dropzone.classList.remove("tiny_ai_dragover")}));const datamanager=(0,_utils.getDatamanager)((0,_utils.getCurrentModalUniqId)(this.baseElement));null!==datamanager.getSelectionImg()&&await this.handleFile(datamanager.getSelectionImg())}async handleFile(file){const reader=new FileReader,_this=this;reader.addEventListener("load",(async()=>{const currentModalUniqid=(0,_utils.getCurrentModalUniqId)(this.baseElement),datamanager=(0,_utils.getDatamanager)(currentModalUniqid),fileUploadedEvent=new CustomEvent("fileUploaded",{detail:{newFile:reader.result}});datamanager.getEventEmitterElement().dispatchEvent(fileUploadedEvent);const ittHandler=(0,_utils.getIttHandler)(currentModalUniqid),allowedMimetypes=await ittHandler.getAllowedMimetypes();if(!allowedMimetypes.includes(file.type)){const errorTitle=await(0,_str.getString)("error_unsupportedfiletype_title","tiny_ai"),errorText=await(0,_str.getString)("error_unsupportedfiletype_text","tiny_ai",allowedMimetypes.toString());return void await(0,_utils.errorAlert)(errorText,errorTitle)}const fileEntryTemplateContext={icon:"application/pdf"===file.type?"fa-file-pdf":"fa-image",filename:file.name?file.name:BasedataHandler.getTinyAiString("imagefromeditor")};file.type.startsWith("image")&&(fileEntryTemplateContext.isImage=!0,fileEntryTemplateContext.dataurl=reader.result);const{html:html,js:js}=await _templates.default.renderForPromise("tiny_ai/components/ai-file-list-entry",fileEntryTemplateContext);_this.setDropzoneContent(html),_templates.default.runTemplateJS(js),_this.dropzone.classList.remove("tiny_ai_dragover"),_this.dropzone.classList.add("tiny_ai_dropzone_filled")}),!1),reader.readAsDataURL(file)}setDropzoneContent(html){this.dropzone.innerHTML=html,this.dropzoneContentToResetTo=html}},_exports.default}));
+define("tiny_ai/controllers/file",["exports","tiny_ai/utils","core/templates","tiny_ai/selectors","tiny_ai/datahandler/basedata","core/str"],(function(_exports,_utils,_templates,_selectors,BasedataHandler,_str){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_templates=_interopRequireDefault(_templates),_selectors=_interopRequireDefault(_selectors),BasedataHandler=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}(BasedataHandler);return _exports.default=class{constructor(baseSelector){_defineProperty(this,"dropzone",null),_defineProperty(this,"dropzoneContentToResetTo",""),this.baseElement=document.querySelector(baseSelector)}async init(){this.dropzone=this.baseElement.querySelector('[data-type="dropzone"]');const dropzone=this.dropzone;dropzone.contentEditable=!0,this.setDropzoneContent(dropzone.innerHTML),dropzone.focus();const _this=this;dropzone.addEventListener("input",(()=>{dropzone.innerHTML!==_this.dropzoneContentToResetTo&&(dropzone.innerHTML=_this.dropzoneContentToResetTo)})),dropzone.addEventListener("drop",(async event=>{if(event.preventDefault(),event.dataTransfer.items){const item=[...event.dataTransfer.items].shift();"file"===item.kind&&await this.handleFile(item.getAsFile())}else await this.handleFile([...event.dataTransfer.files].shift())}));const datamanager=(0,_utils.getDatamanager)((0,_utils.getCurrentModalUniqId)(this.baseElement)),handlePaste=async event=>{if(["describeimg","imagetotext"].includes(datamanager.getCurrentTool())){event.preventDefault();const clipboardData=event.clipboardData||window.clipboardData;if(0===clipboardData.files.length)return void await(0,_utils.errorAlert)(BasedataHandler.getTinyAiString("error_nofileinclipboard_text"),BasedataHandler.getTinyAiString("error_nofileinclipboard_title"));const file=clipboardData.files[0];this.handleFile(file)}};document.querySelector(_selectors.default.modalDialog).removeEventListener("paste",handlePaste),document.querySelector(_selectors.default.modalDialog).addEventListener("paste",handlePaste),dropzone.addEventListener("dragover",(event=>{event.preventDefault(),dropzone.classList.remove("tiny_ai_dropzone_filled"),dropzone.classList.add("tiny_ai_dragover")})),dropzone.addEventListener("dragleave",(event=>{event.preventDefault(),dropzone.classList.remove("tiny_ai_dragover")})),null!==datamanager.getSelectionImg()&&await this.handleFile(datamanager.getSelectionImg())}async handleFile(file){const reader=new FileReader,_this=this;reader.addEventListener("load",(async()=>{const currentModalUniqid=(0,_utils.getCurrentModalUniqId)(this.baseElement),datamanager=(0,_utils.getDatamanager)(currentModalUniqid),fileUploadedEvent=new CustomEvent("fileUploaded",{detail:{newFile:reader.result}});datamanager.getEventEmitterElement().dispatchEvent(fileUploadedEvent);const ittHandler=(0,_utils.getIttHandler)(currentModalUniqid),allowedMimetypes=await ittHandler.getAllowedMimetypes();if(!allowedMimetypes.includes(file.type)){const errorTitle=await(0,_str.getString)("error_unsupportedfiletype_title","tiny_ai"),errorText=await(0,_str.getString)("error_unsupportedfiletype_text","tiny_ai",allowedMimetypes.toString());return void await(0,_utils.errorAlert)(errorText,errorTitle)}const fileEntryTemplateContext={icon:"application/pdf"===file.type?"fa-file-pdf":"fa-image",filename:file.name?file.name:BasedataHandler.getTinyAiString("imagefromeditor")};file.type.startsWith("image")&&(fileEntryTemplateContext.isImage=!0,fileEntryTemplateContext.dataurl=reader.result);const{html:html,js:js}=await _templates.default.renderForPromise("tiny_ai/components/ai-file-list-entry",fileEntryTemplateContext);_this.setDropzoneContent(html),_templates.default.runTemplateJS(js),_this.dropzone.classList.remove("tiny_ai_dragover"),_this.dropzone.classList.add("tiny_ai_dropzone_filled")}),!1),reader.readAsDataURL(file)}setDropzoneContent(html){this.dropzone.innerHTML=html,this.dropzoneContentToResetTo=html}},_exports.default}));
//# sourceMappingURL=file.min.js.map
\ No newline at end of file
diff --git a/amd/build/controllers/file.min.js.map b/amd/build/controllers/file.min.js.map
index 5cd7091..a13e824 100644
--- a/amd/build/controllers/file.min.js.map
+++ b/amd/build/controllers/file.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"file.min.js","sources":["../../src/controllers/file.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 * Controller for handling the show/hide prompt button and the associated textarea.\n *\n * @module tiny_ai/controllers/file\n * @copyright 2024, ISB Bayern\n * @author Philipp Memmel\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {getDatamanager, getCurrentModalUniqId, getIttHandler} from 'tiny_ai/utils';\nimport Templates from 'core/templates';\nimport SELECTORS from 'tiny_ai/selectors';\nimport {errorAlert} from 'tiny_ai/utils';\nimport * as BasedataHandler from 'tiny_ai/datahandler/basedata';\nimport {getString} from 'core/str';\n\n\nexport default class {\n\n dropzone = null;\n dropzoneContentToResetTo = '';\n\n constructor(baseSelector) {\n this.baseElement = document.querySelector(baseSelector);\n }\n\n async init() {\n this.dropzone = this.baseElement.querySelector('[data-type=\"dropzone\"]');\n const dropzone = this.dropzone;\n // Setting contentEditable to true makes the browser show a \"paste\" option in the context menu when\n // right-clicking the drop zone.\n dropzone.contentEditable = true;\n this.setDropzoneContent(dropzone.innerHTML);\n // Instantly focus the drop zone, so you can directly paste the image.\n dropzone.focus();\n\n const _this = this;\n // The drop zone has \"contentEditable\" enabled, so we have to take care of user input\n // and reset the content whenever a user tries to input something.\n dropzone.addEventListener('input', () => {\n if (dropzone.innerHTML !== _this.dropzoneContentToResetTo) {\n dropzone.innerHTML = _this.dropzoneContentToResetTo;\n }\n });\n dropzone.addEventListener('drop', async(event) => {\n event.preventDefault();\n\n if (event.dataTransfer.items) {\n // Use DataTransferItemList interface to access the file(s)\n const item = [...event.dataTransfer.items].shift();\n // If dropped item is no file, reject it.\n if (item.kind === 'file') {\n await this.handleFile(item.getAsFile());\n }\n } else {\n // Use DataTransfer interface to access the file(s)\n await this.handleFile([...event.dataTransfer.files].shift());\n }\n });\n document.querySelector(SELECTORS.modalDialog).addEventListener('paste', async(event) => {\n event.preventDefault();\n const clipboardData = (event.clipboardData || window.clipboardData);\n if (clipboardData.files.length === 0) {\n await errorAlert(BasedataHandler.getTinyAiString('error_nofileinclipboard_text'),\n BasedataHandler.getTinyAiString('error_nofileinclipboard_title'));\n return;\n }\n const file = clipboardData.files[0];\n this.handleFile(file);\n });\n dropzone.addEventListener('dragover', (event) => {\n event.preventDefault();\n dropzone.classList.remove('tiny_ai_dropzone_filled');\n dropzone.classList.add('tiny_ai_dragover');\n });\n dropzone.addEventListener('dragleave', (event) => {\n event.preventDefault();\n dropzone.classList.remove('tiny_ai_dragover');\n });\n\n const datamanager = getDatamanager(getCurrentModalUniqId(this.baseElement));\n if (datamanager.getSelectionImg() !== null) {\n await this.handleFile(datamanager.getSelectionImg());\n }\n }\n\n async handleFile(file) {\n const reader = new FileReader();\n const _this = this;\n reader.addEventListener(\n 'load',\n async() => {\n const currentModalUniqid = getCurrentModalUniqId(this.baseElement);\n const datamanager = getDatamanager(currentModalUniqid);\n const fileUploadedEvent = new CustomEvent('fileUploaded', {\n detail: {\n newFile: reader.result,\n }\n });\n datamanager.getEventEmitterElement().dispatchEvent(fileUploadedEvent);\n const ittHandler = getIttHandler(currentModalUniqid);\n const allowedMimetypes = await ittHandler.getAllowedMimetypes();\n\n if (!allowedMimetypes.includes(file.type)) {\n const errorTitle = await getString('error_unsupportedfiletype_title', 'tiny_ai');\n const errorText = await getString('error_unsupportedfiletype_text', 'tiny_ai', allowedMimetypes.toString());\n await errorAlert(errorText, errorTitle);\n return;\n }\n\n const fileEntryTemplateContext = {\n icon: file.type === 'application/pdf' ? 'fa-file-pdf' : 'fa-image',\n filename: file.name ? file.name : BasedataHandler.getTinyAiString('imagefromeditor'),\n };\n if (file.type.startsWith('image')) {\n fileEntryTemplateContext.isImage = true;\n fileEntryTemplateContext.dataurl = reader.result;\n }\n const {html, js} = await Templates.renderForPromise('tiny_ai/components/ai-file-list-entry',\n fileEntryTemplateContext);\n _this.setDropzoneContent(html);\n // We probably have no JS, but let's be safe here.\n Templates.runTemplateJS(js);\n // There should be no tiny_ai_dragover class, just to be safe.\n _this.dropzone.classList.remove('tiny_ai_dragover');\n _this.dropzone.classList.add('tiny_ai_dropzone_filled');\n },\n false,\n );\n reader.readAsDataURL(file);\n }\n\n setDropzoneContent(html) {\n this.dropzone.innerHTML = html;\n // Keep track of the state.\n this.dropzoneContentToResetTo = html;\n }\n}\n"],"names":["constructor","baseSelector","baseElement","document","querySelector","dropzone","this","contentEditable","setDropzoneContent","innerHTML","focus","_this","addEventListener","dropzoneContentToResetTo","async","event","preventDefault","dataTransfer","items","item","shift","kind","handleFile","getAsFile","files","SELECTORS","modalDialog","clipboardData","window","length","BasedataHandler","getTinyAiString","file","classList","remove","add","datamanager","getSelectionImg","reader","FileReader","currentModalUniqid","fileUploadedEvent","CustomEvent","detail","newFile","result","getEventEmitterElement","dispatchEvent","ittHandler","allowedMimetypes","getAllowedMimetypes","includes","type","errorTitle","errorText","toString","fileEntryTemplateContext","icon","filename","name","startsWith","isImage","dataurl","html","js","Templates","renderForPromise","runTemplateJS","readAsDataURL"],"mappings":"olDAqCIA,YAAYC,8CAHD,sDACgB,SAGlBC,YAAcC,SAASC,cAAcH,gCAIrCI,SAAWC,KAAKJ,YAAYE,cAAc,gCACzCC,SAAWC,KAAKD,SAGtBA,SAASE,iBAAkB,OACtBC,mBAAmBH,SAASI,WAEjCJ,SAASK,cAEHC,MAAQL,KAGdD,SAASO,iBAAiB,SAAS,KAC3BP,SAASI,YAAcE,MAAME,2BAC7BR,SAASI,UAAYE,MAAME,6BAGnCR,SAASO,iBAAiB,QAAQE,MAAAA,WAC9BC,MAAMC,iBAEFD,MAAME,aAAaC,MAAO,OAEpBC,KAAO,IAAIJ,MAAME,aAAaC,OAAOE,QAEzB,SAAdD,KAAKE,YACCf,KAAKgB,WAAWH,KAAKI,wBAIzBjB,KAAKgB,WAAW,IAAIP,MAAME,aAAaO,OAAOJ,YAG5DjB,SAASC,cAAcqB,mBAAUC,aAAad,iBAAiB,SAASE,MAAAA,QACpEC,MAAMC,uBACAW,cAAiBZ,MAAMY,eAAiBC,OAAOD,iBAClB,IAA/BA,cAAcH,MAAMK,yBACd,qBAAWC,gBAAgBC,gBAAgB,gCAC7CD,gBAAgBC,gBAAgB,wCAGlCC,KAAOL,cAAcH,MAAM,QAC5BF,WAAWU,SAEpB3B,SAASO,iBAAiB,YAAaG,QACnCA,MAAMC,iBACNX,SAAS4B,UAAUC,OAAO,2BAC1B7B,SAAS4B,UAAUE,IAAI,uBAE3B9B,SAASO,iBAAiB,aAAcG,QACpCA,MAAMC,iBACNX,SAAS4B,UAAUC,OAAO,6BAGxBE,aAAc,0BAAe,gCAAsB9B,KAAKJ,cACxB,OAAlCkC,YAAYC,yBACN/B,KAAKgB,WAAWc,YAAYC,oCAIzBL,YACPM,OAAS,IAAIC,WACb5B,MAAQL,KACdgC,OAAO1B,iBACH,QACAE,gBACU0B,oBAAqB,gCAAsBlC,KAAKJ,aAChDkC,aAAc,yBAAeI,oBAC7BC,kBAAoB,IAAIC,YAAY,eAAgB,CACtDC,OAAQ,CACJC,QAASN,OAAOO,UAGxBT,YAAYU,yBAAyBC,cAAcN,yBAC7CO,YAAa,wBAAcR,oBAC3BS,uBAAyBD,WAAWE,0BAErCD,iBAAiBE,SAASnB,KAAKoB,MAAO,OACjCC,iBAAmB,kBAAU,kCAAmC,WAChEC,gBAAkB,kBAAU,iCAAkC,UAAWL,iBAAiBM,8BAC1F,qBAAWD,UAAWD,kBAI1BG,yBAA2B,CAC7BC,KAAoB,oBAAdzB,KAAKoB,KAA6B,cAAgB,WACxDM,SAAU1B,KAAK2B,KAAO3B,KAAK2B,KAAO7B,gBAAgBC,gBAAgB,oBAElEC,KAAKoB,KAAKQ,WAAW,WACrBJ,yBAAyBK,SAAU,EACnCL,yBAAyBM,QAAUxB,OAAOO,cAExCkB,KAACA,KAADC,GAAOA,UAAYC,mBAAUC,iBAAiB,wCAChDV,0BACJ7C,MAAMH,mBAAmBuD,yBAEfI,cAAcH,IAExBrD,MAAMN,SAAS4B,UAAUC,OAAO,oBAChCvB,MAAMN,SAAS4B,UAAUE,IAAI,8BAEjC,GAEJG,OAAO8B,cAAcpC,MAGzBxB,mBAAmBuD,WACV1D,SAASI,UAAYsD,UAErBlD,yBAA2BkD"}
\ No newline at end of file
+{"version":3,"file":"file.min.js","sources":["../../src/controllers/file.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 * Controller for handling the show/hide prompt button and the associated textarea.\n *\n * @module tiny_ai/controllers/file\n * @copyright 2024, ISB Bayern\n * @author Philipp Memmel\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {getDatamanager, getCurrentModalUniqId, getIttHandler} from 'tiny_ai/utils';\nimport Templates from 'core/templates';\nimport SELECTORS from 'tiny_ai/selectors';\nimport {errorAlert} from 'tiny_ai/utils';\nimport * as BasedataHandler from 'tiny_ai/datahandler/basedata';\nimport {getString} from 'core/str';\n\n\nexport default class {\n\n dropzone = null;\n dropzoneContentToResetTo = '';\n\n constructor(baseSelector) {\n this.baseElement = document.querySelector(baseSelector);\n }\n\n async init() {\n this.dropzone = this.baseElement.querySelector('[data-type=\"dropzone\"]');\n const dropzone = this.dropzone;\n // Setting contentEditable to true makes the browser show a \"paste\" option in the context menu when\n // right-clicking the drop zone.\n dropzone.contentEditable = true;\n this.setDropzoneContent(dropzone.innerHTML);\n // Instantly focus the drop zone, so you can directly paste the image.\n dropzone.focus();\n\n const _this = this;\n // The drop zone has \"contentEditable\" enabled, so we have to take care of user input\n // and reset the content whenever a user tries to input something.\n dropzone.addEventListener('input', () => {\n if (dropzone.innerHTML !== _this.dropzoneContentToResetTo) {\n dropzone.innerHTML = _this.dropzoneContentToResetTo;\n }\n });\n dropzone.addEventListener('drop', async(event) => {\n event.preventDefault();\n\n if (event.dataTransfer.items) {\n // Use DataTransferItemList interface to access the file(s)\n const item = [...event.dataTransfer.items].shift();\n // If dropped item is no file, reject it.\n if (item.kind === 'file') {\n await this.handleFile(item.getAsFile());\n }\n } else {\n // Use DataTransfer interface to access the file(s)\n await this.handleFile([...event.dataTransfer.files].shift());\n }\n });\n\n const datamanager = getDatamanager(getCurrentModalUniqId(this.baseElement));\n\n const handlePaste = async(event) => {\n // We have to be careful. We are registering this listener globally onto the modal dialog to catch all the\n // paste events. We have to ensure we do not interfere with pasting into text fields of other tools though.\n if (['describeimg', 'imagetotext'].includes(datamanager.getCurrentTool())) {\n event.preventDefault();\n const clipboardData = (event.clipboardData || window.clipboardData);\n if (clipboardData.files.length === 0) {\n await errorAlert(BasedataHandler.getTinyAiString('error_nofileinclipboard_text'),\n BasedataHandler.getTinyAiString('error_nofileinclipboard_title'));\n return;\n }\n const file = clipboardData.files[0];\n this.handleFile(file);\n }\n };\n // Avoid re-adding event paste listener.\n document.querySelector(SELECTORS.modalDialog).removeEventListener('paste', handlePaste);\n document.querySelector(SELECTORS.modalDialog).addEventListener('paste', handlePaste);\n dropzone.addEventListener('dragover', (event) => {\n event.preventDefault();\n dropzone.classList.remove('tiny_ai_dropzone_filled');\n dropzone.classList.add('tiny_ai_dragover');\n });\n dropzone.addEventListener('dragleave', (event) => {\n event.preventDefault();\n dropzone.classList.remove('tiny_ai_dragover');\n });\n\n if (datamanager.getSelectionImg() !== null) {\n await this.handleFile(datamanager.getSelectionImg());\n }\n }\n\n async handleFile(file) {\n const reader = new FileReader();\n const _this = this;\n reader.addEventListener(\n 'load',\n async() => {\n const currentModalUniqid = getCurrentModalUniqId(this.baseElement);\n const datamanager = getDatamanager(currentModalUniqid);\n const fileUploadedEvent = new CustomEvent('fileUploaded', {\n detail: {\n newFile: reader.result,\n }\n });\n datamanager.getEventEmitterElement().dispatchEvent(fileUploadedEvent);\n const ittHandler = getIttHandler(currentModalUniqid);\n const allowedMimetypes = await ittHandler.getAllowedMimetypes();\n\n if (!allowedMimetypes.includes(file.type)) {\n const errorTitle = await getString('error_unsupportedfiletype_title', 'tiny_ai');\n const errorText = await getString('error_unsupportedfiletype_text', 'tiny_ai', allowedMimetypes.toString());\n await errorAlert(errorText, errorTitle);\n return;\n }\n\n const fileEntryTemplateContext = {\n icon: file.type === 'application/pdf' ? 'fa-file-pdf' : 'fa-image',\n filename: file.name ? file.name : BasedataHandler.getTinyAiString('imagefromeditor'),\n };\n if (file.type.startsWith('image')) {\n fileEntryTemplateContext.isImage = true;\n fileEntryTemplateContext.dataurl = reader.result;\n }\n const {html, js} = await Templates.renderForPromise('tiny_ai/components/ai-file-list-entry',\n fileEntryTemplateContext);\n _this.setDropzoneContent(html);\n // We probably have no JS, but let's be safe here.\n Templates.runTemplateJS(js);\n // There should be no tiny_ai_dragover class, just to be safe.\n _this.dropzone.classList.remove('tiny_ai_dragover');\n _this.dropzone.classList.add('tiny_ai_dropzone_filled');\n },\n false,\n );\n reader.readAsDataURL(file);\n }\n\n setDropzoneContent(html) {\n this.dropzone.innerHTML = html;\n // Keep track of the state.\n this.dropzoneContentToResetTo = html;\n }\n}\n"],"names":["constructor","baseSelector","baseElement","document","querySelector","dropzone","this","contentEditable","setDropzoneContent","innerHTML","focus","_this","addEventListener","dropzoneContentToResetTo","async","event","preventDefault","dataTransfer","items","item","shift","kind","handleFile","getAsFile","files","datamanager","handlePaste","includes","getCurrentTool","clipboardData","window","length","BasedataHandler","getTinyAiString","file","SELECTORS","modalDialog","removeEventListener","classList","remove","add","getSelectionImg","reader","FileReader","currentModalUniqid","fileUploadedEvent","CustomEvent","detail","newFile","result","getEventEmitterElement","dispatchEvent","ittHandler","allowedMimetypes","getAllowedMimetypes","type","errorTitle","errorText","toString","fileEntryTemplateContext","icon","filename","name","startsWith","isImage","dataurl","html","js","Templates","renderForPromise","runTemplateJS","readAsDataURL"],"mappings":"olDAqCIA,YAAYC,8CAHD,sDACgB,SAGlBC,YAAcC,SAASC,cAAcH,gCAIrCI,SAAWC,KAAKJ,YAAYE,cAAc,gCACzCC,SAAWC,KAAKD,SAGtBA,SAASE,iBAAkB,OACtBC,mBAAmBH,SAASI,WAEjCJ,SAASK,cAEHC,MAAQL,KAGdD,SAASO,iBAAiB,SAAS,KAC3BP,SAASI,YAAcE,MAAME,2BAC7BR,SAASI,UAAYE,MAAME,6BAGnCR,SAASO,iBAAiB,QAAQE,MAAAA,WAC9BC,MAAMC,iBAEFD,MAAME,aAAaC,MAAO,OAEpBC,KAAO,IAAIJ,MAAME,aAAaC,OAAOE,QAEzB,SAAdD,KAAKE,YACCf,KAAKgB,WAAWH,KAAKI,wBAIzBjB,KAAKgB,WAAW,IAAIP,MAAME,aAAaO,OAAOJ,kBAItDK,aAAc,0BAAe,gCAAsBnB,KAAKJ,cAExDwB,YAAcZ,MAAAA,WAGZ,CAAC,cAAe,eAAea,SAASF,YAAYG,kBAAmB,CACvEb,MAAMC,uBACAa,cAAiBd,MAAMc,eAAiBC,OAAOD,iBAClB,IAA/BA,cAAcL,MAAMO,yBACd,qBAAWC,gBAAgBC,gBAAgB,gCAC7CD,gBAAgBC,gBAAgB,wCAGlCC,KAAOL,cAAcL,MAAM,QAC5BF,WAAWY,QAIxB/B,SAASC,cAAc+B,mBAAUC,aAAaC,oBAAoB,QAASX,aAC3EvB,SAASC,cAAc+B,mBAAUC,aAAaxB,iBAAiB,QAASc,aACxErB,SAASO,iBAAiB,YAAaG,QACnCA,MAAMC,iBACNX,SAASiC,UAAUC,OAAO,2BAC1BlC,SAASiC,UAAUE,IAAI,uBAE3BnC,SAASO,iBAAiB,aAAcG,QACpCA,MAAMC,iBACNX,SAASiC,UAAUC,OAAO,uBAGQ,OAAlCd,YAAYgB,yBACNnC,KAAKgB,WAAWG,YAAYgB,oCAIzBP,YACPQ,OAAS,IAAIC,WACbhC,MAAQL,KACdoC,OAAO9B,iBACH,QACAE,gBACU8B,oBAAqB,gCAAsBtC,KAAKJ,aAChDuB,aAAc,yBAAemB,oBAC7BC,kBAAoB,IAAIC,YAAY,eAAgB,CACtDC,OAAQ,CACJC,QAASN,OAAOO,UAGxBxB,YAAYyB,yBAAyBC,cAAcN,yBAC7CO,YAAa,wBAAcR,oBAC3BS,uBAAyBD,WAAWE,0BAErCD,iBAAiB1B,SAASO,KAAKqB,MAAO,OACjCC,iBAAmB,kBAAU,kCAAmC,WAChEC,gBAAkB,kBAAU,iCAAkC,UAAWJ,iBAAiBK,8BAC1F,qBAAWD,UAAWD,kBAI1BG,yBAA2B,CAC7BC,KAAoB,oBAAd1B,KAAKqB,KAA6B,cAAgB,WACxDM,SAAU3B,KAAK4B,KAAO5B,KAAK4B,KAAO9B,gBAAgBC,gBAAgB,oBAElEC,KAAKqB,KAAKQ,WAAW,WACrBJ,yBAAyBK,SAAU,EACnCL,yBAAyBM,QAAUvB,OAAOO,cAExCiB,KAACA,KAADC,GAAOA,UAAYC,mBAAUC,iBAAiB,wCAChDV,0BACJhD,MAAMH,mBAAmB0D,yBAEfI,cAAcH,IAExBxD,MAAMN,SAASiC,UAAUC,OAAO,oBAChC5B,MAAMN,SAASiC,UAAUE,IAAI,8BAEjC,GAEJE,OAAO6B,cAAcrC,MAGzB1B,mBAAmB0D,WACV7D,SAASI,UAAYyD,UAErBrD,yBAA2BqD"}
\ No newline at end of file
diff --git a/amd/src/controllers/file.js b/amd/src/controllers/file.js
index 5c2f24e..f3c5f42 100644
--- a/amd/src/controllers/file.js
+++ b/amd/src/controllers/file.js
@@ -72,17 +72,27 @@ export default class {
await this.handleFile([...event.dataTransfer.files].shift());
}
});
- document.querySelector(SELECTORS.modalDialog).addEventListener('paste', async(event) => {
- event.preventDefault();
- const clipboardData = (event.clipboardData || window.clipboardData);
- if (clipboardData.files.length === 0) {
- await errorAlert(BasedataHandler.getTinyAiString('error_nofileinclipboard_text'),
- BasedataHandler.getTinyAiString('error_nofileinclipboard_title'));
- return;
+
+ const datamanager = getDatamanager(getCurrentModalUniqId(this.baseElement));
+
+ const handlePaste = async(event) => {
+ // We have to be careful. We are registering this listener globally onto the modal dialog to catch all the
+ // paste events. We have to ensure we do not interfere with pasting into text fields of other tools though.
+ if (['describeimg', 'imagetotext'].includes(datamanager.getCurrentTool())) {
+ event.preventDefault();
+ const clipboardData = (event.clipboardData || window.clipboardData);
+ if (clipboardData.files.length === 0) {
+ await errorAlert(BasedataHandler.getTinyAiString('error_nofileinclipboard_text'),
+ BasedataHandler.getTinyAiString('error_nofileinclipboard_title'));
+ return;
+ }
+ const file = clipboardData.files[0];
+ this.handleFile(file);
}
- const file = clipboardData.files[0];
- this.handleFile(file);
- });
+ };
+ // Avoid re-adding event paste listener.
+ document.querySelector(SELECTORS.modalDialog).removeEventListener('paste', handlePaste);
+ document.querySelector(SELECTORS.modalDialog).addEventListener('paste', handlePaste);
dropzone.addEventListener('dragover', (event) => {
event.preventDefault();
dropzone.classList.remove('tiny_ai_dropzone_filled');
@@ -93,7 +103,6 @@ export default class {
dropzone.classList.remove('tiny_ai_dragover');
});
- const datamanager = getDatamanager(getCurrentModalUniqId(this.baseElement));
if (datamanager.getSelectionImg() !== null) {
await this.handleFile(datamanager.getSelectionImg());
}