Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
// This file is part of Moodle - http://moodle.org/
2
//
3
// Moodle is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// Moodle is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
 
16
/**
17
 * Tiny media plugin embed thumbnail upload class.
18
 *
19
 * This handles the embed thumbnail upload using drag-drop.
20
 *
21
 * @module      tiny_media/embed/embedthumbnailinsert
22
 * @copyright   2024 Stevani Andolo <stevani@hotmail.com.au>
23
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 */
25
 
26
import Selectors from '../selectors';
27
import Dropzone from 'core/dropzone';
28
import uploadFile from 'editor_tiny/uploader';
29
import {prefetchStrings} from 'core/prefetch';
30
import {getStrings} from 'core/str';
31
import {component} from "../common";
32
import {
33
    showElements,
34
    startMediaLoading,
35
    stopMediaLoading,
36
    setPropertiesFromData,
37
    body,
38
    footer,
39
} from '../helpers';
40
import {EmbedThumbnailPreview} from './embedthumbnailpreview';
41
import {EmbedHandler} from './embedhandler';
42
import {displayFilepicker} from 'editor_tiny/utils';
43
 
44
prefetchStrings(component, [
45
    'insertmediathumbnail',
46
    'uploading',
47
    'loadingembedthumbnail',
48
    'addmediathumbnaildrop',
49
]);
50
 
51
export class EmbedThumbnailInsert {
52
 
53
    constructor(data) {
54
        setPropertiesFromData(this, data); // Creates dynamic properties based on "data" param.
55
    }
56
 
57
    /**
58
     * Init the dropzone and lang strings.
59
     *
60
     * @param {object} mediaData Object of selected media data
61
     */
62
    init = async(mediaData) => {
63
        this.mediaData = mediaData; // Current selected media data passed from embedPreview.
64
        const langStringKeys = [
65
            'insertmediathumbnail',
66
            'uploading',
67
            'loadingembedthumbnail',
68
            'addmediathumbnaildrop',
69
        ];
70
        const langStringvalues = await getStrings([...langStringKeys].map((key) => ({key, component})));
71
        this.langStrings = Object.fromEntries(langStringKeys.map((key, index) => [key, langStringvalues[index]]));
72
        this.currentModal.uploadThumbnailModal.setTitle(this.langStrings.insertmediathumbnail);
73
 
74
        // Let's init the dropzone if canShowDropZone is true.
75
        if (this.canShowDropZone) {
76
            const dropZoneEle = document.querySelector(Selectors.EMBED.elements.dropzoneContainer);
77
            const dropZone = new Dropzone(
78
                dropZoneEle,
79
                this.acceptedImageTypes,
80
                files => {
81
                    this.handleUploadedFile(files);
82
                }
83
            );
84
            dropZone.setLabel(this.langStrings.addmediathumbnaildrop);
85
            dropZone.init();
86
        }
87
 
88
        this.registerInsertMediaThumbnailEvents(this.thumbnailModalRoot);
89
    };
90
 
91
    /**
92
     * Load and display a preview thumbnail based on the provided URL, and handles thumbnail loading events.
93
     *
94
     * @param {string} url - The URL of the thumbnail to load and display.
95
     */
96
    loadPreviewThumbnail = (url) => {
97
        this.media.poster = url;
98
 
99
        let templateContext = {
100
            bodyTemplate: Selectors.EMBED.template.body.mediaThumbnailBody,
101
            footerTemplate: Selectors.EMBED.template.footer.mediaThumbnailFooter,
102
            selector: Selectors.EMBED.type,
103
        };
104
 
105
        Promise.all([body(templateContext, this.thumbnailModalRoot), footer(templateContext, this.thumbnailModalRoot)])
106
            .then(() => {
107
                const mediaThumbnail = new EmbedThumbnailPreview(this);
108
                mediaThumbnail.init(this.mediaData);
109
                return;
110
            })
111
            .catch(error => {
112
                window.console.log(error);
113
            });
114
    };
115
 
116
    /**
117
     * Handles media preview on file picker callback.
118
     *
119
     * @param {object} params Object of uploaded file
120
     */
121
    filePickerCallback = (params) => {
122
        if (params.url) {
123
            this.loadPreviewThumbnail(params.url);
124
        }
125
    };
126
 
127
    /**
128
     * Updates the content of the loader icon.
129
     *
130
     * @param {HTMLElement} root - The root element containing the loader icon.
131
     * @param {object} langStrings - An object containing language strings.
132
     * @param {number|null} progress - The progress percentage (optional).
133
     */
134
    updateLoaderIcon = (root, langStrings, progress = null) => {
135
        const loaderIconState = root.querySelector(Selectors.EMBED.elements.loaderIconContainer + ' div');
136
        loaderIconState.innerHTML = (progress !== null) ?
137
                               `${langStrings.uploading} ${Math.round(progress)}%` :
138
                               langStrings.loadingembedthumbnail;
139
    };
140
 
141
    /**
142
     * Handles changes in the media URL input field and loads a preview of the media if the URL has changed.
143
     */
144
    urlChanged() {
145
        const url = this.thumbnailModalRoot.querySelector(Selectors.EMBED.elements.fromUrl).value;
146
        if (url && url !== this.currentUrl) {
147
            this.loadPreviewThumbnail(url);
148
        }
149
    }
150
 
151
    /**
152
     * Handles the uploaded file, initiates the upload process, and updates the UI during the upload.
153
     *
154
     * @param {FileList} files - The list of files to upload (usually from a file input field).
155
     * @returns {Promise<void>} A promise that resolves when the file is uploaded and processed.
156
     */
157
    handleUploadedFile = async(files) => {
158
        try {
159
            startMediaLoading(this.thumbnailModalRoot, Selectors.EMBED.type);
160
            const fileURL = await uploadFile(this.editor, 'image', files[0], files[0].name, (progress) => {
161
                this.updateLoaderIcon(this.thumbnailModalRoot, this.langStrings, progress);
162
            });
163
 
164
            // Set the loader icon content to "loading" after the file upload completes.
165
            this.updateLoaderIcon(this.thumbnailModalRoot, this.langStrings);
166
            this.filePickerCallback({url: fileURL});
167
        } catch (error) {
168
            // Handle the error.
169
            const urlWarningLabelEle = this.thumbnailModalRoot.querySelector(Selectors.EMBED.elements.urlWarning);
170
            urlWarningLabelEle.innerHTML = error.error !== undefined ? error.error : error;
171
            showElements(Selectors.EMBED.elements.urlWarning, this.thumbnailModalRoot);
172
            stopMediaLoading(this.thumbnailModalRoot, Selectors.EMBED.type);
173
        }
174
    };
175
 
176
    /**
177
     * Registers events for insert thumbnail modal.
178
     *
179
     * @param {HTMLElement} root - The root element containing the loader icon.
180
     */
181
    registerInsertMediaThumbnailEvents = (root) => {
182
        const urlEle = root.querySelector(Selectors.EMBED.elements.fromUrl);
183
        if (urlEle) {
184
            urlEle.addEventListener('input', () => {
185
                (new EmbedHandler(this)).toggleUrlButton(urlEle, this.thumbnailModalRoot);
186
            });
187
        }
188
 
189
        // Handles add media url.
190
        const addUrlEle = root.querySelector(Selectors.EMBED.actions.addUrl);
191
        if (addUrlEle) {
192
            addUrlEle.addEventListener('click', () => {
193
                startMediaLoading(this.thumbnailModalRoot, Selectors.EMBED.type);
194
                this.urlChanged();
195
            });
196
        }
197
 
198
        // Handle repository browsing.
199
        const imageBrowser = root.querySelector(Selectors.IMAGE.actions.imageBrowser);
200
        if (imageBrowser) {
201
            imageBrowser.addEventListener('click', async(e) => {
202
                e.preventDefault();
203
                const params = await displayFilepicker(this.editor, 'image');
204
                this.filePickerCallback(params);
205
            });
206
        }
207
    };
208
}