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!