Recently, I made an exam system that used rich text editing to edit the questions, and required the ability to add images, videos, and PDFS. WangEditor was used in previous projects. When using it, I found that only local pictures could be uploaded, and only links could be added to videos. I found other plug-ins, but I did not find any good ones. So I looked at the source code.

One, achieve the effect

Implementation effect

Second, the source

Below is the wangEditor implementation code for inserting a video

function Video(editor) {
    this.editor = editor;
    this.$elem = $('<div class="w-e-menu"><i class="w-e-icon-play"></i></div>');
    this.type = 'panel';

    // Whether the current state is active
    this._active = false;
}

/ / prototype
Video.prototype = {
    constructor: Video,
    
    onClick: function onClick() {
        this._createPanel();
    },
    
    _createPanel: function _createPanel() {
        var _this = this;

        / / create the id
        var textValId = getRandom('text-val');
        var btnId = getRandom('btn');

        / / create a panel
        var panel = new Panel(this, {
            width: 350.// A panel with multiple tabs
            tabs: [{
                / / title
                title: 'Insert video'./ / template
                tpl: '<div><input id="' + textValId + '" type="text" class="block" placeholder="\u683C\u5F0F\u5982\uFF1A<iframe src=... ></iframe>"/><div class="w-e-button-container"><button id="' + btnId + '" class="right">\u63D2\u5165</button></div></div>'.// Event binding
                events: [{
                    selector: The '#' + btnId,
                    type: 'click'.fn: function fn() {
                        var $text = $(The '#' + textValId);
                        var val = $text.val().trim();

                        if (val) _this._insert(val); // Insert the video

                        // Returns true, indicating that the panel should be closed after the event. Otherwise the panel won't close
                        return true; }}}]]// tabs end
        }); // panel end

        / / display panel
        panel.show();

        // Record attributes
        this.panel = panel;
    }
    
    // Insert the video
    _insert: function _insert(val) {
        var editor = this.editor;
        editor.cmd.do('insertHTML', val + '<p><br></p>'); }};Copy the code

Three, implementation,

After looking at the source code found very simple, in the creation of a panel to add a panel to insert video, then to achieve a video upload, insert editor is done, refer to the file upload code.

1. Add Insert video Panel

Modify the video.prototype. _createPanel method

_createPanel: function _createPanel() {
    var _this = this;
    var editor = this.editor;
    var uploadImg = editor.uploadImg;
    var config = editor.config;

    / / create the id
    // Upload the video ID
    var upTriggerVideoId = getRandom('up-trigger-video');
    var upFileVideoId = getRandom('up-file-video');
    // Insert the video ID
    var textValId = getRandom('text-val');
    var btnId = getRandom('btn');

    // Tabs configuration
    var tabsConfig = [
        {
            title: 'Upload video or PDF'.tpl: '<div class="w-e-up-img-container"><div id="' + upTriggerVideoId + '" class="w-e-up-btn">
      
+ upFileVideoId + '" type="file" multiple="multiple" accept="application/pdf,video/*"/></div></div>'.events: [{ // Trigger image selection selector: The '#' + upTriggerVideoId, type: 'click'.fn: function fn() { var $file = $(The '#' + upFileVideoId); var fileElem = $file[0]; if (fileElem) { fileElem.click(); } else { // Returns true to close panel return true; }}}, {// Select the image selector: The '#' + upFileVideoId, type: 'change'.fn: function fn() { var $file = $(The '#' + upFileVideoId); var fileElem = $file[0]; if(! fileElem) {// Returns true to close panel return true; } // Get the list of selected file objects var fileList = fileElem.files; if (fileList.length) { console.log(fileList); uploadImg.uploadVideo(fileList); } // Returns true to close panel return true; }}},// first tab end { / / title title: 'Insert video'./ / template tpl: '<div><input id="' + textValId + '" type="text" class="block" placeholder="\u683C\u5F0F\u5982\uFF1A<iframe src=... ></iframe>"/><div class="w-e-button-container"><button id="' + btnId + '" class="right">\u63D2\u5165</button></div></div>'.// Event binding events: [{ selector: The '#' + btnId, type: 'click'.fn: function fn() { var $text = $(The '#' + textValId); var val = $text.val().trim(); if (val) _this._insert(val); // Insert the video // Returns true, indicating that the panel should be closed after the event. Otherwise the panel won't close return true; }}}]// second tab end ]; // tabs end // Determine the tabs display var tabsConfigResult = []; if (config.uploadVideoServer) { // Display "Upload video" tabsConfigResult.push(tabsConfig[0]); } if (config.showLinkVideo) { // Display network video tabsConfigResult.push(tabsConfig[1]); } / / create a panel var panel = new Panel(this, { width: 350.// A panel with multiple tabs tabs: tabsConfigResult // tabs end }); // panel end / / display panel panel.show(); // Record attributes this.panel = panel; } Copy the code

2. Upload files

Image upload method implemented in UploadImg UploadImg, consult, in adding a uploadVideo UploadImg method.

// Upload the video
UploadImg.prototype.uploadVideo: function uploadVideo(files) {
    var _this3 = this;

    if(! files || ! files.length) {return;
    }

    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- get configuration information -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
    var editor = this.editor;
    var config = editor.config;
    var uploadVideoServer = config.uploadVideoServer;

    var maxSize = config.uploadVideoMaxSize;
    var maxSizeM = maxSize / 1024 / 1024;
    var maxLength = config.uploadVideoMaxLength || 10000;
    var uploadFileName = config.uploadFileName || ' ';
    var uploadVideoParams = config.uploadVideoParams || {};
    var uploadVideoParamsWithUrl = config.uploadVideoParamsWithUrl;
    var uploadVideoHeaders = config.uploadVideoHeaders || {};
    var hooks = config.uploadVideoHooks || {};
    var timeout = config.uploadVideoTimeout || 30 * 60 * 1000; / / for 30 minutes
    var withCredentials = config.withCredentials;
    if (withCredentials == null) {
        withCredentials = false;
    }
    var customUploadVideo = config.customUploadVideo;

    if(! customUploadVideo) {// Without customUploadVideo, the following two configurations are required to continue uploading images
        if(! uploadVideoServer) {return; }}/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- validation file information -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
    var resultFiles = [];
    var errInfo = [];
    arrForEach(files, function (file) {
        var name = file.name;
        var size = file.size;

        // Name === undefined
        if(! name || ! size) {return;
        }

        if (/\.(pdf|rm|rmvb|3gp|avi|mpeg|mpg|mkv|dat|asf|wmv|flv|mov|mp4|ogg|ogm)$/i.test(name) === false) {
            // Invalid suffix, not video
            errInfo.push('\u3010' + name + '\u3011\u4E0D\u662F\u56FE\u7247');
            return;
        }
        if (maxSize < size) {
            // Upload video is too large
            errInfo.push('\u3010' + name + '\u3011\u5927\u4E8E ' + maxSizeM + 'M');
            return;
        }

        // Join result list if the verification passes
        resultFiles.push(file);
    });
    // Throws validation information
    if (errInfo.length) {
        this._alert('Video verification failed: \n' + errInfo.join('\n'));
        return;
    }
    if (resultFiles.length > maxLength) {
        this._alert('Upload at most once' + maxLength + 'A video');
        return;
    }

    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- custom upload -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    if (customUploadVideo && typeof customUploadVideo === 'function') {
        customUploadVideo(resultFiles, this.insertLinkVideo.bind(this));

        // Block the following code from executing
        return;
    }

    // Add image data
    var formdata = new FormData();
    arrForEach(resultFiles, function (file) {
        var name = uploadFileName || file.name;
        formdata.append(name, file);
    });

    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- to upload pictures -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    if (uploadVideoServer && typeof uploadVideoServer === 'string') {
        // Add parameters
        var uploadVideoServerArr = uploadVideoServer.split(The '#');
        uploadVideoServer = uploadVideoServerArr[0];
        var uploadVideoServerHash = uploadVideoServerArr[1] | |' ';
        objForEach(uploadVideoParams, function (key, val) {
            // Due to user reaction, custom parameters can not default encode, from v3.1.1 annotations out
            // val = encodeURIComponent(val)

            // First, concatenate the parameters into the URL
            if (uploadVideoParamsWithUrl) {
                if (uploadVideoServer.indexOf('? ') > 0) {
                    uploadVideoServer += '&';
                } else {
                    uploadVideoServer += '? ';
                }
                uploadVideoServer = uploadVideoServer + key + '=' + val;
            }

            // Second, add the parameters to formData
            formdata.append(key, val);
        });
        if (uploadVideoServerHash) {
            uploadVideoServer += The '#' + uploadVideoServerHash;
        }

        / / define XHR
        var xhr = new XMLHttpRequest();
        xhr.open('POST', uploadVideoServer);

        // Set timeout
        xhr.timeout = timeout;
        xhr.ontimeout = function () {
            // hook - timeout
            if (hooks.timeout && typeof hooks.timeout === 'function') {
                hooks.timeout(xhr, editor);
            }

            _this3._alert('Upload video timed out');
        };

        / / monitor progress
        if (xhr.upload) {
            xhr.upload.onprogress = function (e) {
                var percent = void 0;
                / / the progress bar
                var progressBar = new Progress(editor);
                if(e.lengthComputable) { percent = e.loaded / e.total; progressBar.show(percent); }}; }// Return data
        xhr.onreadystatechange = function () {
            var result = void 0;
            if (xhr.readyState === 4) {
                if (xhr.status < 200 || xhr.status >= 300) {
                    // hook - error
                    if (hooks.error && typeof hooks.error === 'function') {
                        hooks.error(xhr, editor);
                    }

                    // XHR returns a status error
                    _this3._alert('Error uploading video'.'\u4E0A\u4F20\u56FE\u7247\u53D1\u751F\u9519\u8BEF\uFF0C\u670D\u52A1\u5668\u8FD4\u56DE\u72B6\u6001\u662F ' + xhr.status);
                    return;
                }

                result = xhr.responseText;
                if ((typeof result === 'undefined' ? 'undefined': _typeof(result)) ! = ='object') {
                    try {
                        result = JSON.parse(result);
                    } catch (ex) {
                        // hook - fail
                        if (hooks.fail && typeof hooks.fail === 'function') {
                            hooks.fail(xhr, editor, result);
                        }

                        _this3._alert('Failed to upload video'.'Error in uploading video, return result:' + result);
                        return; }}if(! hooks.customInsert && result.errno ! ='0') {
                    // hook - fail
                    if (hooks.fail && typeof hooks.fail === 'function') {
                        hooks.fail(xhr, editor, result);
                    }

                    // Data error
                    _this3._alert('Failed to upload video'.'Error message returned from uploading video, errno=' + result.errno);
                } else {
                    if (hooks.customInsert && typeof hooks.customInsert === 'function') {
                        // User-defined insert method
                        hooks.customInsert(_this3.insertLinkVideo.bind(_this3), result, editor);
                    } else {
                        // Insert the image into the editor
                        var data = result.data || [];
                        data.forEach(function (link) {
                            _this3.insertLinkVideo(link);
                        });
                    }

                    // hook - success
                    if (hooks.success && typeof hooks.success === 'function') { hooks.success(xhr, editor, result); }}}};// hook - before
        if (hooks.before && typeof hooks.before === 'function') {
            var beforeResult = hooks.before(xhr, editor, resultFiles);
            if (beforeResult && (typeof beforeResult === 'undefined' ? 'undefined' : _typeof(beforeResult)) === 'object') {
                if (beforeResult.prevent) {
                    // If {prevent: true, MSG: 'XXXX '} is returned, the user has abandoned uploading
                    this._alert(beforeResult.msg);
                    return; }}}// Customize headers
        objForEach(uploadVideoHeaders, function (key, val) {
            xhr.setRequestHeader(key, val);
        });

        // Send cookies across domains
        xhr.withCredentials = withCredentials;

        // Send the requestxhr.send(formdata); }}Copy the code

Insert the editor

The insert video is also written in Uploadimg. prototype

// Insert the video according to the link
insertLinkVideo: function insertLinkVideo(link) {
    if(! link)return;
    
    var _this2 = this;

    var editor = this.editor;
    var config = editor.config;

    // Verify format
    var linkVideoCheck = config.linkVideoCheck;
    var checkResult = void 0;
    if (linkVideoCheck && typeof linkVideoCheck === 'function') {
        checkResult = linkVideoCheck(link);
        if (typeof checkResult === 'string') {
            // The verification fails
            alert(checkResult);
            return;
        }
    }

    editor.cmd.do('insertHTML'.'<iframe src="' + link + '" style="width:650px; height: 366px" frameborder="0">');
}
Copy the code

4. Add default video upload parameters

Add some default parameters of uploaded video in config. It doesn’t matter whether you add them or not. Parameter judgment has been made in the use method.

// Whether to display the TAB for adding network video
showLinkVideo: true.// Insert the network video callback
linkVideoCallback: function linkVideoCallback(url) {
    // console.log(url) // url is the address to insert the video
},

// Upload videos Max size: 512 MB by default
uploadVideoMaxSize: 512 * 1024 * 1024.// Upload a maximum of several videos at a time
uploadVideoMaxLength: 5.// Upload video custom parameters
uploadVideoParams: {
    // token: 'abcdef12345'
},

// Upload a custom header for the video
uploadVideoHeaders: {
    // 'Accept': 'text/x-json'
},

// Customize the video upload timeout period of 30 minutes
uploadVideoTimeout: 30 * 60 * 1000.// Upload video hook
uploadVideoHooks: {
    // customInsert: function (insertLinkVideo, result, editor) {
    // console.log('customInsert')
    // // Video uploads and returns results, customizing the event of inserting the video instead of the editor automatically inserting the video
    // const data = result.data1 || []
    // data.forEach(link => {
    // insertLinkVideo(link)
    / /})
    // },
    before: function before(xhr, editor, files) {
        // Triggered before the video is uploaded

        // If {prevent: true, MSG: 'XXXX '} is returned, the user has abandoned uploading
        // return {
        // prevent: true,
        // MSG: 'abort upload'
        // }
    },
    success: function success(xhr, editor, result) {
        // Upload the video and return the result
    },
    fail: function fail(xhr, editor, result) {
        // Video uploads and returns results, but is triggered when the video is inserted incorrectly
    },
    error: function error(xhr, editor) {
        // When an error occurs on the video
    },
    timeout: function timeout(xhr, editor) {
        // Video upload times out}}Copy the code

Four, the use of

Initialize the editor and set the parameters for uploading the video

var editor = new window.wangEditor('#text-editor');
// Image upload
editor.customConfig.uploadImgServer = 'upload/editUpload'; // Upload interface
editor.customConfig.uploadFileName = 'files'; // Upload file parameter name
editor.customConfig.uploadImgHooks = { // Upload complete processing method
    customInsert: function (insertImg, result) {
        if (result.ret === 200) {
            (result.data || ' ').split(', ').forEach(function (link) {
                link && insertImg(link);
            });
        } else {
            flavrShowByTime('Upload failed'.null.'danger'); }}};// Video upload
editor.customConfig.uploadVideoServer = 'editUpload'; // Upload interface
editor.customConfig.uploadVideoHooks = { // Upload complete processing method
    customInsert: function (insertVideo, result) {
        if (result.ret === 200) {
            (result.data || ' ').split(', ').forEach(function (link) {
                link && insertVideo(link);
            });
        } else {
            flavrShowByTime('Upload failed'.null.'danger'); }}}; editor.create();Copy the code

Write at the end

Originally did not want to change the source code, want to directly rewrite some of the methods in the use of Video._createPanel, UploadImg, insertImg, etc.. However, neither Panel nor UploadImg is mounted to the instance when the instance is called. So can only modify the source code. In this way! Over! Writing articles is no good!