lib/editor/tiny/plugins/link/amd/src/ui.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/>.

/**
 * Tiny Link UI.
 *
 * @module      tiny_link/ui
 * @copyright   2023 Huong Nguyen <huongnv13@gmail.com>
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

import {getFilePicker} from 'editor_tiny/options';
import {displayFilepicker} from 'editor_tiny/utils';
import LinkModal from 'tiny_link/modal';
import {getPermissions} from "tiny_link/options";
import {setLink, getCurrentLinkData, unSetLink} from "tiny_link/link";
import Selectors from 'tiny_link/selectors';

/**
 * Handle action.
 *
 * @param {TinyMCE} editor
 * @param {boolean} unlink
 */
export const handleAction = (editor, unlink = false) => {
    if (!unlink) {
        displayDialogue(editor);
    } else {
        unSetLink(editor);
    }
};

/**
 * Display the link dialogue.
 *
 * @param {TinyMCE} editor
 * @returns {Promise<void>}
 */
const displayDialogue = async(editor) => {
    const modal = await LinkModal.create({
        templateContext: getTemplateContext(editor),
    });

    const $root = await modal.getRoot();
    const root = $root[0];
    const currentForm = root.querySelector('form');

    root.addEventListener('click', (e) => {
        const submitAction = e.target.closest(Selectors.actions.submit);
        const linkBrowserAction = e.target.closest(Selectors.actions.linkBrowser);
        if (submitAction) {
            e.preventDefault();
            setLink(currentForm, editor);
            modal.destroy();
        }
        if (linkBrowserAction) {
            e.preventDefault();
            displayFilepicker(editor, 'link').then((params) => {
                filePickerCallback(params, currentForm, editor);
                return modal.destroy();
            }).catch();
        }
    });

    const linkTitle = root.querySelector(Selectors.elements.urlText);
    const linkUrl = root.querySelector(Selectors.elements.urlEntry);
    linkTitle.addEventListener('change', () => {
        if (linkTitle.value.length > 0) {
            linkTitle.dataset.useLinkAsText = 'false';
        } else {
            linkTitle.dataset.useLinkAsText = 'true';
            linkTitle.value = linkUrl.value;
        }
    });

    linkUrl.addEventListener('keyup', () => {
        updateTextToDisplay(currentForm);
    });
};

/**
 * Get template context.
 *
 * @param {TinyMCE} editor
 * @returns {Object}
 */
const getTemplateContext = (editor) => {
    const data = getCurrentLinkData(editor);

    return Object.assign({}, {
        elementid: editor.id,
        showfilepicker: getPermissions(editor).filepicker &&
            (typeof getFilePicker(editor, 'link') !== 'undefined'),
        isupdating: Object.keys(data).length > 0,
    }, data);
};

/**
 * Update the dialogue after a link was selected in the File Picker.
 *
 * @param {Object} params
 * @param {Element} currentForm
 * @param {TinyMCE} editor
 */
const filePickerCallback = (params, currentForm, editor) => {
    if (params.url) {
        const inputUrl = currentForm.querySelector(Selectors.elements.urlEntry);
        inputUrl.value = params.url;
        setLink(currentForm, editor);
    }
};

/**
 * Update the text to display if the user does not provide the custom text.
 *
 * @param {Element} currentForm
 */
const updateTextToDisplay = (currentForm) => {
    const urlEntry = currentForm.querySelector(Selectors.elements.urlEntry);
    const urlText = currentForm.querySelector(Selectors.elements.urlText);
    if (urlText.dataset.useLinkAsText === 'true') {
        urlText.value = urlEntry.value;
    }
};