Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
{"version":3,"file":"generateimage.min.js","sources":["../src/generateimage.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 <http://www.gnu.org/licenses/>.\n\n/**\n * Tiny AI generate images.\n *\n * @module      tiny_aiplacement/generateimage\n * @copyright   2024 Matt Porritt <matt.porritt@moodle.com>\n * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ImageModal from 'tiny_aiplacement/imagemodal';\nimport Ajax from 'core/ajax';\nimport {getString} from 'core/str';\nimport Templates from 'core/templates';\nimport AiMediaImage from './mediaimage';\nimport {getContextId} from 'tiny_aiplacement/options';\nimport GenerateBase from 'tiny_aiplacement/generatebase';\n\nexport default class GenerateImage extends GenerateBase {\n    SELECTORS = {\n        GENERATEBUTTON: () => `[id=\"${this.editor.id}_tiny_aiplacement_generatebutton\"]`,\n        PROMPTAREA: () => `[id=\"${this.editor.id}_tiny_aiplacement_imageprompt\"]`,\n        IMAGECONTAINER: () => `[id=\"${this.editor.id}_tiny_aiplacement_generate_image\"]`,\n        GENERATEBTN: '[data-action=\"generate\"]',\n        INSERTBTN: '[data-action=\"inserter\"]',\n        BACKTBTN: '[data-action=\"back\"]',\n        GENERATEDIMAGE: () => `[id=\"${this.editor.id}_tiny_generated_image\"]`,\n    };\n\n    imageURL = null;\n\n    getModalClass() {\n        return ImageModal;\n    }\n\n    /**\n     * Handle click events within the image modal.\n     *\n     * @param {Event} e - The click event object.\n     * @param {HTMLElement} root - The root element of the modal.\n     */\n    handleContentModalClick(e, root) {\n        const actions = {\n            generate: () => this.handleSubmit(root, e.target),\n            inserter: () => this.handleInsert(),\n            cancel: () => this.modalObject.destroy(),\n            back: () => {\n                this.modalObject.destroy();\n                this.displayContentModal();\n            },\n        };\n\n        const actionKey = Object.keys(actions).find(key => e.target.closest(`[data-action=\"${key}\"]`));\n        if (actionKey) {\n            e.preventDefault();\n            actions[actionKey]();\n        }\n    }\n\n    /**\n     * Set up the prompt area in the modal, adding necessary event listeners.\n     *\n     * @param {HTMLElement} root - The root element of the modal.\n     */\n    setupPromptArea(root) {\n        const generateBtn = root.querySelector(this.SELECTORS.GENERATEBUTTON());\n        const promptArea = root.querySelector(this.SELECTORS.PROMPTAREA());\n\n        promptArea.addEventListener('input', () => {\n            generateBtn.disabled = promptArea.value.trim() === '';\n        });\n    }\n\n    /**\n     * Handle the submit action.\n     *\n     * @param {Object} root The root element of the modal.\n     * @param {Object} submitBtn The submit button element.\n     */\n    async handleSubmit(root, submitBtn) {\n        await this.displayLoading(root, submitBtn);\n\n        const displayArgs = this.getDisplayArgs(root);\n        const request = {\n            methodname: 'aiplacement_editor_generate_image',\n            args: displayArgs\n        };\n\n        try {\n            this.responseObj = await Ajax.call([request])[0];\n            if (this.responseObj.error) {\n                this.handleGenerationError(root, submitBtn, '');\n            } else {\n                await this.displayGeneratedImage(root);\n                await this.hideLoading(root, submitBtn);\n                // Focus the container for accessibility.\n                const imageDisplayContainer = root.querySelector(this.SELECTORS.IMAGECONTAINER());\n                imageDisplayContainer.focus();\n            }\n        } catch (error) {\n            this.handleGenerationError(root, submitBtn, '');\n        }\n    }\n\n    /**\n     * Handle the insert action.\n     *\n     */\n    async handleInsert() {\n        // Use the revised prompt for the image alt text if it is available in the response.\n        const revisedPrompt = this.responseObj.revisedprompt;\n        const altTextToUse = revisedPrompt ? revisedPrompt : this.promptText;\n        const mediaImage = new AiMediaImage(this.editor, this.imageURL, altTextToUse);\n        await mediaImage.displayDialogue();\n        this.modalObject.destroy();\n    }\n\n    /**\n     * Handle a generation error.\n     *\n     * @param {Object} root The root element of the modal.\n     * @param {Object} submitBtn The submit button element.\n     * @param {String} errorMessage The error message to display.\n     */\n    async handleGenerationError(root, submitBtn, errorMessage = '') {\n        if (!errorMessage) {\n            // Get the default error message.\n            errorMessage = await getString('errorgeneral', 'tiny_aiplacement');\n        }\n        this.modalObject.setBody(await Templates.render('tiny_aiplacement/modalbodyerror', {'errorMessage': errorMessage}));\n        const backBtn = root.querySelector(this.SELECTORS.BACKTBTN);\n        const generateBtn = root.querySelector(this.SELECTORS.GENERATEBUTTON());\n        backBtn.classList.remove('hidden');\n        generateBtn.classList.add('hidden');\n        await this.hideLoading(root, submitBtn);\n        // Focus the back button for accessibility.\n        backBtn.focus();\n    }\n\n    /**\n     * Display the generated image in the modal.\n     *\n     * @param {HTMLElement} root - The root element of the modal.\n     */\n    async displayGeneratedImage(root) {\n        const imageDisplayContainer = root.querySelector(this.SELECTORS.IMAGECONTAINER());\n        const insertBtn = root.querySelector(this.SELECTORS.INSERTBTN);\n        // Set the draft URL as it's used elsewhere.\n        this.imageURL = this.responseObj.drafturl;\n\n        // Render the image template and insert it into the modal.\n        imageDisplayContainer.innerHTML = await Templates.render('tiny_aiplacement/image', {\n            url: this.responseObj.drafturl,\n            elementid: this.editor.id,\n            alt: this.promptText,\n        });\n        const imagElement = root.querySelector(this.SELECTORS.GENERATEDIMAGE());\n\n        return new Promise((resolve, reject) => {\n            imagElement.onload = () => {\n                insertBtn.classList.remove('hidden');\n                imagElement.focus();\n                resolve(); // Resolve the promise when the image is loaded.\n            };\n            imagElement.onerror = (error) => {\n                reject(error); // Reject the promise if there is an error loading the image.\n            };\n        });\n    }\n\n    /**\n     * Get the display args for the image.\n     *\n     * @param {Object} root The root element of the modal.\n     */\n    getDisplayArgs(root) {\n        const contextId = getContextId(this.editor);\n        const promptText = root.querySelector(this.SELECTORS.PROMPTAREA()).value;\n        this.promptText = promptText;\n\n        const aspectRatio = this.getSelectedRadioValue('aspect-ratio', 'square');\n        const imageQuality = this.getSelectedRadioValue('quality', 'standard');\n\n        return {\n            contextid: contextId,\n            prompttext: promptText,\n            aspectratio: aspectRatio,\n            quality: imageQuality,\n            numimages: 1\n        };\n    }\n\n    /**\n     * Get the value of the selected radio button.\n     *\n     * @param {String} radioName The name of the radio button group.\n     * @param {String} defaultValue The default value of the radio button.\n     */\n    getSelectedRadioValue(radioName, defaultValue = null) {\n        const radios = document.getElementsByName(radioName);\n        for (const radio of radios) {\n            if (radio.checked) {\n                return radio.value;\n            }\n        }\n        return defaultValue;\n    }\n}\n"],"names":["GenerateImage","GenerateBase","GENERATEBUTTON","this","editor","id","PROMPTAREA","IMAGECONTAINER","GENERATEBTN","INSERTBTN","BACKTBTN","GENERATEDIMAGE","getModalClass","ImageModal","handleContentModalClick","e","root","actions","generate","handleSubmit","target","inserter","handleInsert","cancel","modalObject","destroy","back","displayContentModal","actionKey","Object","keys","find","key","closest","preventDefault","setupPromptArea","generateBtn","querySelector","SELECTORS","promptArea","addEventListener","disabled","value","trim","submitBtn","displayLoading","request","methodname","args","getDisplayArgs","responseObj","Ajax","call","error","handleGenerationError","displayGeneratedImage","hideLoading","focus","revisedPrompt","revisedprompt","altTextToUse","promptText","mediaImage","AiMediaImage","imageURL","displayDialogue","errorMessage","setBody","Templates","render","backBtn","classList","remove","add","imageDisplayContainer","insertBtn","drafturl","innerHTML","url","elementid","alt","imagElement","Promise","resolve","reject","onload","onerror","contextId","contextid","prompttext","aspectratio","getSelectedRadioValue","quality","numimages","radioName","defaultValue","radios","document","getElementsByName","radio","checked"],"mappings":"+0BA+BqBA,sBAAsBC,yFAC3B,CACRC,eAAgB,mBAAcC,KAAKC,OAAOC,yCAC1CC,WAAY,mBAAcH,KAAKC,OAAOC,sCACtCE,eAAgB,mBAAcJ,KAAKC,OAAOC,yCAC1CG,YAAa,2BACbC,UAAW,2BACXC,SAAU,uBACVC,eAAgB,mBAAcR,KAAKC,OAAOC,gEAGnC,MAEXO,uBACWC,oBASXC,wBAAwBC,EAAGC,YACjBC,QAAU,CACZC,SAAU,IAAMf,KAAKgB,aAAaH,KAAMD,EAAEK,QAC1CC,SAAU,IAAMlB,KAAKmB,eACrBC,OAAQ,IAAMpB,KAAKqB,YAAYC,UAC/BC,KAAM,UACGF,YAAYC,eACZE,wBAIPC,UAAYC,OAAOC,KAAKb,SAASc,MAAKC,KAAOjB,EAAEK,OAAOa,gCAAyBD,aACjFJ,YACAb,EAAEmB,iBACFjB,QAAQW,cAShBO,gBAAgBnB,YACNoB,YAAcpB,KAAKqB,cAAclC,KAAKmC,UAAUpC,kBAChDqC,WAAavB,KAAKqB,cAAclC,KAAKmC,UAAUhC,cAErDiC,WAAWC,iBAAiB,SAAS,KACjCJ,YAAYK,SAAuC,KAA5BF,WAAWG,MAAMC,6BAU7B3B,KAAM4B,iBACfzC,KAAK0C,eAAe7B,KAAM4B,iBAG1BE,QAAU,CACZC,WAAY,oCACZC,KAHgB7C,KAAK8C,eAAejC,mBAO/BkC,kBAAoBC,cAAKC,KAAK,CAACN,UAAU,GAC1C3C,KAAK+C,YAAYG,WACZC,sBAAsBtC,KAAM4B,UAAW,QACzC,OACGzC,KAAKoD,sBAAsBvC,YAC3Bb,KAAKqD,YAAYxC,KAAM4B,WAEC5B,KAAKqB,cAAclC,KAAKmC,UAAU/B,kBAC1CkD,SAE5B,MAAOJ,YACAC,sBAAsBtC,KAAM4B,UAAW,gCAU1Cc,cAAgBvD,KAAK+C,YAAYS,cACjCC,aAAeF,eAAgCvD,KAAK0D,WACpDC,WAAa,IAAIC,oBAAa5D,KAAKC,OAAQD,KAAK6D,SAAUJ,oBAC1DE,WAAWG,uBACZzC,YAAYC,sCAUOT,KAAM4B,eAAWsB,oEAAe,GACnDA,eAEDA,mBAAqB,kBAAU,eAAgB,0BAE9C1C,YAAY2C,cAAcC,mBAAUC,OAAO,kCAAmC,cAAiBH,sBAC9FI,QAAUtD,KAAKqB,cAAclC,KAAKmC,UAAU5B,UAC5C0B,YAAcpB,KAAKqB,cAAclC,KAAKmC,UAAUpC,kBACtDoE,QAAQC,UAAUC,OAAO,UACzBpC,YAAYmC,UAAUE,IAAI,gBACpBtE,KAAKqD,YAAYxC,KAAM4B,WAE7B0B,QAAQb,oCAQgBzC,YAClB0D,sBAAwB1D,KAAKqB,cAAclC,KAAKmC,UAAU/B,kBAC1DoE,UAAY3D,KAAKqB,cAAclC,KAAKmC,UAAU7B,gBAE/CuD,SAAW7D,KAAK+C,YAAY0B,SAGjCF,sBAAsBG,gBAAkBT,mBAAUC,OAAO,yBAA0B,CAC/ES,IAAK3E,KAAK+C,YAAY0B,SACtBG,UAAW5E,KAAKC,OAAOC,GACvB2E,IAAK7E,KAAK0D,mBAERoB,YAAcjE,KAAKqB,cAAclC,KAAKmC,UAAU3B,yBAE/C,IAAIuE,SAAQ,CAACC,QAASC,UACzBH,YAAYI,OAAS,KACjBV,UAAUJ,UAAUC,OAAO,UAC3BS,YAAYxB,QACZ0B,WAEJF,YAAYK,QAAWjC,QACnB+B,OAAO/B,WAUnBJ,eAAejC,YACLuE,WAAY,yBAAapF,KAAKC,QAC9ByD,WAAa7C,KAAKqB,cAAclC,KAAKmC,UAAUhC,cAAcoC,WAC9DmB,WAAaA,iBAKX,CACH2B,UAAWD,UACXE,WAAY5B,WACZ6B,YANgBvF,KAAKwF,sBAAsB,eAAgB,UAO3DC,QANiBzF,KAAKwF,sBAAsB,UAAW,YAOvDE,UAAW,GAUnBF,sBAAsBG,eAAWC,oEAAe,WACtCC,OAASC,SAASC,kBAAkBJ,eACrC,MAAMK,SAASH,UACZG,MAAMC,eACCD,MAAMzD,aAGdqD"}