| 1 | efrain | 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 class for Moodle.
 | 
        
           |  |  | 18 |  *
 | 
        
           |  |  | 19 |  * @module      tiny_media/embed
 | 
        
           |  |  | 20 |  * @copyright   2022 Huong Nguyen <huongnv13@gmail.com>
 | 
        
           |  |  | 21 |  * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 22 |  */
 | 
        
           |  |  | 23 |   | 
        
           |  |  | 24 | import EmbedModal from './embedmodal';
 | 
        
           |  |  | 25 | import {getEmbedPermissions} from './options';
 | 
        
           | 1441 | ariadna | 26 | import {getFilePicker, getContextId} from 'editor_tiny/options';
 | 
        
           |  |  | 27 | import {EmbedHandler} from './embed/embedhandler';
 | 
        
           |  |  | 28 | import {insertMediaTemplateContext, getSelectedMediaElement} from './embed/embedhelpers';
 | 
        
           |  |  | 29 | import {EmbedInsert} from './embed/embedinsert';
 | 
        
           |  |  | 30 | import {startMediaLoading} from './helpers';
 | 
        
           |  |  | 31 | import Selectors from "./selectors";
 | 
        
           | 1 | efrain | 32 |   | 
        
           |  |  | 33 | export default class MediaEmbed {
 | 
        
           |  |  | 34 |     editor = null;
 | 
        
           |  |  | 35 |     canShowFilePicker = false;
 | 
        
           |  |  | 36 |     canShowFilePickerTrack = false;
 | 
        
           | 1441 | ariadna | 37 |     canShowDropZone = false;
 | 
        
           | 1 | efrain | 38 |   | 
        
           |  |  | 39 |     constructor(editor) {
 | 
        
           |  |  | 40 |         const permissions = getEmbedPermissions(editor);
 | 
        
           | 1441 | ariadna | 41 |         const options = getFilePicker(editor, 'media');
 | 
        
           | 1 | efrain | 42 |   | 
        
           |  |  | 43 |         // Indicates whether the file picker can be shown.
 | 
        
           | 1441 | ariadna | 44 |         this.canShowFilePicker = permissions.filepicker
 | 
        
           |  |  | 45 |             && (typeof options !== 'undefined')
 | 
        
           |  |  | 46 |             && Object.keys(options.repositories).length > 0;
 | 
        
           | 1 | efrain | 47 |         this.canShowFilePickerTrack = permissions.filepicker && (typeof getFilePicker(editor, 'subtitle') !== 'undefined');
 | 
        
           | 1441 | ariadna | 48 |         this.canShowDropZone = Object.values(options.repositories).some(repository => repository.type === 'upload');
 | 
        
           |  |  | 49 |         this.editor = editor;
 | 
        
           |  |  | 50 |         this.acceptedMediaTypes = options.accepted_types;
 | 
        
           |  |  | 51 |         this.contextId = getContextId(editor);
 | 
        
           | 1 | efrain | 52 |   | 
        
           | 1441 | ariadna | 53 |         // Image options.
 | 
        
           |  |  | 54 |         const imageOptions = getFilePicker(editor, 'image');
 | 
        
           |  |  | 55 |         this.acceptedImageTypes = imageOptions.accepted_types;
 | 
        
           |  |  | 56 |         this.canShowImageFilePicker = permissions.filepicker
 | 
        
           |  |  | 57 |             && (typeof imageOptions !== 'undefined')
 | 
        
           |  |  | 58 |             && Object.keys(imageOptions.repositories).length > 0;
 | 
        
           | 1 | efrain | 59 |     }
 | 
        
           |  |  | 60 |   | 
        
           | 1441 | ariadna | 61 |     /**
 | 
        
           |  |  | 62 |      * Displays media modal accordingly.
 | 
        
           |  |  | 63 |      */
 | 
        
           |  |  | 64 |     displayDialogue = async() => {
 | 
        
           |  |  | 65 |         const [mediaType, selectedMedia] = getSelectedMediaElement(this.editor);
 | 
        
           |  |  | 66 |         this.mediaType = mediaType;
 | 
        
           |  |  | 67 |         this.selectedMedia = selectedMedia;
 | 
        
           | 1 | efrain | 68 |   | 
        
           | 1441 | ariadna | 69 |         if (this.selectedMedia) {
 | 
        
           |  |  | 70 |             // Preview the selected media.
 | 
        
           |  |  | 71 |             this.isUpdating = true;
 | 
        
           |  |  | 72 |             this.loadSelectedMedia();
 | 
        
           |  |  | 73 |         } else {
 | 
        
           |  |  | 74 |             // Create media modal.
 | 
        
           |  |  | 75 |             await this.createMediaModal();
 | 
        
           |  |  | 76 |             // Load insert media modal.
 | 
        
           |  |  | 77 |             await this.loadInsertMediaModal();
 | 
        
           | 1 | efrain | 78 |         }
 | 
        
           | 1441 | ariadna | 79 |     };
 | 
        
           | 1 | efrain | 80 |   | 
        
           | 1441 | ariadna | 81 |     /**
 | 
        
           |  |  | 82 |      * Load insert media modal.
 | 
        
           |  |  | 83 |      */
 | 
        
           |  |  | 84 |     loadInsertMediaModal = async() => {
 | 
        
           |  |  | 85 |         const embedHandler = new EmbedHandler(this);
 | 
        
           |  |  | 86 |         embedHandler.loadTemplatePromise(insertMediaTemplateContext(this));
 | 
        
           |  |  | 87 |         await embedHandler.registerEventListeners();
 | 
        
           |  |  | 88 |     };
 | 
        
           | 1 | efrain | 89 |   | 
        
           | 1441 | ariadna | 90 |     /**
 | 
        
           |  |  | 91 |      * Create media modal.
 | 
        
           |  |  | 92 |      */
 | 
        
           |  |  | 93 |     createMediaModal = async() => {
 | 
        
           | 1 | efrain | 94 |         this.currentModal = await EmbedModal.create({
 | 
        
           | 1441 | ariadna | 95 |             large: true,
 | 
        
           |  |  | 96 |             templateContext: {elementid: this.editor.getElement().id},
 | 
        
           | 1 | efrain | 97 |         });
 | 
        
           | 1441 | ariadna | 98 |         this.modalRoot = this.currentModal.getRoot();
 | 
        
           |  |  | 99 |         this.root = this.modalRoot[0];
 | 
        
           |  |  | 100 |     };
 | 
        
           | 1 | efrain | 101 |   | 
        
           | 1441 | ariadna | 102 |     /**
 | 
        
           |  |  | 103 |      * Load media preview based on the selected media.
 | 
        
           |  |  | 104 |      */
 | 
        
           |  |  | 105 |     loadSelectedMedia = async() => {
 | 
        
           |  |  | 106 |         let mediaSource = null;
 | 
        
           |  |  | 107 |         if (['video', 'audio'].includes(this.mediaType)) {
 | 
        
           |  |  | 108 |             mediaSource = this.selectedMedia.querySelector('source').src;
 | 
        
           |  |  | 109 |             // If the selected media has more than one sources, it has main source and alternative sources.
 | 
        
           |  |  | 110 |             const sources = this.selectedMedia.querySelectorAll('source');
 | 
        
           |  |  | 111 |             if (sources.length > 1) {
 | 
        
           |  |  | 112 |                 let alternativeSources = [];
 | 
        
           |  |  | 113 |                 Object.keys(sources).forEach(function(source) {
 | 
        
           |  |  | 114 |                     alternativeSources.push(sources[source].src);
 | 
        
           |  |  | 115 |                 });
 | 
        
           |  |  | 116 |                 this.alternativeSources = alternativeSources; // Used to later check if the embedded media has alternative sources.
 | 
        
           | 1 | efrain | 117 |             }
 | 
        
           | 1441 | ariadna | 118 |         } else if (this.selectedMedia.classList.contains(Selectors.EMBED.externalMediaProvider)) {
 | 
        
           |  |  | 119 |             mediaSource = this.selectedMedia.href;
 | 
        
           |  |  | 120 |             this.mediaType = 'link';
 | 
        
           | 1 | efrain | 121 |         }
 | 
        
           |  |  | 122 |   | 
        
           | 1441 | ariadna | 123 |         // Load media preview.
 | 
        
           |  |  | 124 |         if (this.mediaType) {
 | 
        
           |  |  | 125 |             // Create media modal.
 | 
        
           |  |  | 126 |             await this.createMediaModal();
 | 
        
           |  |  | 127 |             // Start the spinner.
 | 
        
           |  |  | 128 |             startMediaLoading(this.root, Selectors.EMBED.type);
 | 
        
           | 1 | efrain | 129 |   | 
        
           | 1441 | ariadna | 130 |             const embedInsert = new EmbedInsert(this);
 | 
        
           |  |  | 131 |             embedInsert.init();
 | 
        
           |  |  | 132 |             embedInsert.loadMediaPreview(mediaSource);
 | 
        
           |  |  | 133 |             await (new EmbedHandler(this)).registerEventListeners();
 | 
        
           |  |  | 134 |         } else {
 | 
        
           |  |  | 135 |             // Create media modal.
 | 
        
           |  |  | 136 |             await this.createMediaModal();
 | 
        
           |  |  | 137 |             // Load insert media modal.
 | 
        
           |  |  | 138 |             this.loadInsertMediaModal();
 | 
        
           | 1 | efrain | 139 |         }
 | 
        
           | 1441 | ariadna | 140 |     };
 | 
        
           | 1 | efrain | 141 | }
 |