repository/googledocs/amd/src/upload.js

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Upload module for Google Docs repository.
 *
 * @module     repository_googledocs/upload
 * @copyright  2025 Huong Nguyen <huongnv13@gmail.com>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

import {subscribe} from 'core/pubsub';
import SaveCancelModal from 'core/modal_save_cancel';
import {getString} from 'core/str';
import Templates from 'core/templates';
import ModalEvents from 'core/modal_events';
import Dropzone from 'core/dropzone';
import * as config from 'core/config';
import Notification from 'core/notification';

let listenersRegistered = false;
let droppedFiles = [];

/**
 * Open the upload modal.
 *
 * @param {object} data Data passed from the event
 */
const openUploadModal = (data) => {
    Templates.render('repository_googledocs/upload_dialogue', {}).then(function(bodyHtml) {
        return SaveCancelModal.create({
            title: getString('upload'),
            body: bodyHtml,
            large: true,
        }).then(function(modal) {
            modal.getRoot().on(ModalEvents.shown, () => {
                droppedFiles = [];
                initDropzone(modal);
            });
            modal.getRoot().on(ModalEvents.hidden, () => {
                modal.destroy();
            });
            modal.getRoot().on(ModalEvents.save, (e) => {
                e.preventDefault();
                commitFiles(data.repoId, data.contextId, data.callback, droppedFiles, modal);
            });
            modal.getRoot().on(ModalEvents.cancel, () => {
                modal.hide();
            });
            modal.show();

            return modal;
        });
    });
};

/**
 * Initialize the dropzone inside the modal.
 *
 * @param {Modal} modal Modal instance
 */
const initDropzone = (modal) => {
    const $body = modal.getBody();
    const dropzoneContainer = $body.find('.repository_googledocs_dropzone_container').get(0);
    const fileListContainer = $body.find('ul.repository_googledocs_files_list').get(0);
    const dz = new Dropzone(dropzoneContainer, '*', (files) => {
        droppedFiles.push(...files);
        let fileListHTML = '';
        for (let i = 0; i < droppedFiles.length; i++) {
            fileListHTML += '<li>' + droppedFiles[i].name + '</li>';
        }
        fileListContainer.innerHTML = fileListHTML;
    });

    getString('dropfiles', 'repository').then((label) => {
        dz.setLabel(label);
    });

    dz.init();
};

/**
 * Upload files to server.
 *
 * @param {Integer} repoId Repository ID
 * @param {Integer} contextId Context ID
 * @param {function} callback Callback function
 * @param {array} files Files to be uploaded
 * @param {Modal} modal Modal instance
 */
const commitFiles = (repoId, contextId, callback, files, modal) => {
    const saveButton = modal.getFooter().find('[data-action="save"]');
    const formData = new FormData();
    formData.append('action', 'upload');
    formData.append('repo_id', repoId);
    formData.append('contextid', contextId);
    formData.append('sesskey', config.sesskey);
    for (let i = 0; i < files.length; i++) {
        formData.append("files[]", files[i]);
    }
    const xhr = new XMLHttpRequest();
    xhr.open('POST', config.wwwroot + '/repository/googledocs/repository_ajax.php', false);
    xhr.onload = function() {
        const response = JSON.parse(xhr.responseText);
        if (response.error) {
            saveButton.removeAttr('disabled');
            Notification.alert(
                getString('uploaderror', 'repository'),
                response.error,
                getString('close', 'repository'),
            );
        } else {
            saveButton.removeAttr('disabled');
            modal.hide();
            callback();
        }
    };
    xhr.send(formData);
};

/**
 * Register events.
 */
const registerEventListeners = () => {
    if (!listenersRegistered) {
        subscribe('repository_googledocs_upload', (data) => {
            openUploadModal(data);
        });
        listenersRegistered = true;
    }
};

/**
 * Initializes the upload module.
 */
export const init = () => {
    registerEventListeners();
};