ueditor编辑器二次开发与优化
在线管理给图片增加删除按钮
修改/DjangoUeditor/static/ueditor/dialogs/image/image.js
... item.appendChild(icon);/*增加删除功能开始*/ span= document.createElement('span'); span.setAttribute("url",list[i].url); span.innerText="X"; domUtils.addClass(span, 'delbtn'); domUtils.on(span, 'click', (function(span){return function(){try{window.event.cancelBubble = true; //停止冒泡window.event.returnValue = false; //阻止事件的默认行为window.event.preventDefault(); //取消事件的默认行为window.event.stopPropagation(); //阻止事件的传播} finally {if(!confirm("确定要删除吗?")) return;$.post(editor.getOpt("serverUrl") + "&action=delete_site_file", { "path": span.getAttribute("url") }, function(result) {if (result == "ok") domUtils.remove(span.parentNode,false);else alert(result);});}} })(span)); item.appendChild(span); /*增加删除功能结束*/ this.list.insertBefore(item, this.clearFloat);
在/DjangoUeditor/static/ueditor/dialogs/image/image.css增加以下内容:
/* 在线管理删除按钮样式 */ #online li span.delbtn {position: absolute;top: 0;right: 0;border: 0;z-index: 3;color: #ffffff;display: inline;font-size: 12px;line-height: 10.5px;padding:3px 5px;text-align: center;background-color: #d9534f; }
增加图片删除后台逻辑
由于DjangoUeditor并没有提供文件删除的action,需要自己添加,可移步前往djangoUeditor优化问题查看如何添加action修改后效果
视频大小可读性
上面的图是上传5G的视频显示的视频大小,显然可读性太差。可以修改/ueditor/dialogs/video/video.js
里面的updateStatus
函数的
WebUploader.formatSize(fileSize)
改为如下:
WebUploader.formatSize(fileSize,['M'])
具体效果如下:
添加视频封面
ueditor并没有实现视频上传封面的功能,但是经过博主测试,研究出下面操作是可以实现视频上传添加封面,但是视频上传封面并不是在视频上传的时候指定的,而是在视频上传完成后再实现的,具体实现操作如下:
首先修改ueditor.all.js里面的上传视频插件内容为如下:
UE.plugins['video'] = function (){var me =this;/*** 创建插入视频字符窜* @param url 视频地址* @param width 视频宽度* @param height 视频高度* @param align 视频对齐* @param classname 标签class值* @param type 类型(video、image、audio、embed)* @param poster 视频封面*/function creatInsertStr(url,width,height,id,align,classname,type,poster){var str;switch (type){case 'image':str = '<img ' + (id ? 'id="' + id+'"' : '') + ' width="'+ width +'" height="' + height + '" _url="'+utils.html(url)+'" class="' + classname.replace(/\bvideo-js\b/, '') + '"' +(poster ? ' src="'+poster+'" ':' src="'+ me.options.UEDITOR_HOME_URL+'themes/default/images/videologo.gif"')+(poster ? ' _src="'+poster+'" ':' _src="'+ me.options.UEDITOR_HOME_URL+'themes/default/images/videologo.gif"')+(align ? ' style="float:' + align + ';"': '')+'/>'break;case 'video':str = '<video' + (id ? ' id="' + id + '"' : '') + ' class="' + classname + ' video-js" ' + (align ? ' style="float:' + align + '"': ' ') +(poster ? ' poster="'+poster+'" ':' poster="'+ me.options.UEDITOR_HOME_URL+'themes/default/images/videologo.gif"')+(poster ? ' _src="'+poster+'" ':' _src="'+ me.options.UEDITOR_HOME_URL+'themes/default/images/videologo.gif"')+' controls preload="none" width="' + width + '" height="' + height + '" src="' + utils.html(url)+'" _url="'+utils.html(url)+ '">' +'</video>';break;}return str;}/**** @param root 根节点* @param img2video 为true表示image转video,为false表示video转image*/function switchImgAndVideo(root,img2video){console.log(img2video);utils.each(root.getNodesByTagName(img2video ? 'img' : 'video'),function(node){var className = node.getAttr('class');console.log("align:"+node.getStyle('float'));if(className && className.indexOf('fake-video') != -1){console.log(node);console.log(node.getAttr("_src"));var html = creatInsertStr( node.getAttr('_url'),node.getAttr('width'),node.getAttr('height'),null,node.getStyle('float') || '',className,img2video ? 'video':"image",node.getAttr("_src"));console.log(html);node.parentNode.replaceChild(UE.uNode.createElement(html),node);}if(className && className.indexOf('upload-video') != -1){var html = creatInsertStr( node.getAttr('_url'),node.getAttr('width'),node.getAttr('height'),null,node.getStyle('float') || '',className,img2video ? 'video':"image",node.getAttr("_src"));console.log(html);node.parentNode.replaceChild(UE.uNode.createElement(html),node);}})}me.addOutputRule(function(root){switchImgAndVideo(root,true)});me.addInputRule(function(root){switchImgAndVideo(root)});me.commands["insertvideo"] = {execCommand: function (cmd, videoObjs, type){videoObjs = utils.isArray(videoObjs)?videoObjs:[videoObjs];var html = [],id = 'tmpVedio',cl;//for(var i=0,vi,len = videoObjs.length;i<len;i++){vi = videoObjs[i];cl = (type == 'upload' ? 'upload-video video-js vjs-default-skin':'fake-video');var temp=creatInsertStr( vi.url,vi.width || 420, vi.height || 280,id + i, vi.align, cl, 'image',vi.poster);html.push(temp);}me.execCommand("inserthtml",html.join(""));var rng = this.selection.getRange();for(var i= 0,len=videoObjs.length;i<len;i++){var img = this.document.getElementById('tmpVedio'+i);domUtils.removeAttributes(img,'id');rng.selectNode(img).select();me.execCommand('imagefloat',videoObjs[i].align)}},queryCommandState : function(){var video = me.selection.getRange().getClosedNode(),flag = video && (video.className == "fake-video" || video.className.indexOf("upload-video")!=-1);return flag ? 1 : 0;}};
};
修改video.js里面的内容为如下
function initVideo(){createAlignButton( ["videoFloat", "upload_alignment"] );addUrlChangeListener($G("videoUrl"), $G("videoPoster"));addOkListener();//编辑视频时初始化相关信息(function(){var node = editor.selection.getRange().getClosedNode(),url;if(node && node.className){var hasInsertClass = node.className.indexOf("fake-video")!=-1,hasUploadClass = node.className.indexOf("upload-video")!=-1,poster=node.getAttribute("_src");if(hasInsertClass || hasUploadClass) {$G("videoUrl").value = url = node.getAttribute("_url");$G("videoWidth").value = node.width;$G("videoHeight").value = node.height;$G("videoPoster").value =poster ;var align = domUtils.getComputedStyle(node,"float"),parentAlign = domUtils.getComputedStyle(node.parentNode,"text-align");updateAlignButton(parentAlign==="center"?"center":align);}if(hasUploadClass) {isModifyUploadVideo = true;}}createPreviewVideo(url,poster);})();
}function createPreviewVideo(url,poster){if ( !url )return;var conUrl = convert_url(url);$G("preview").innerHTML = '<div class="previewMsg"><span>'+lang.urlError+'</span></div>'+'<video class="previewVideo" controls ' +' src="' + conUrl + '"' +' width="' + 420 + '"' +' height="' + 280 +'"'+' poster="'+poster+'">' +'</video>';
}
选中内容区刚上传的视频如下:
然后在弹出的图片上传对话框下选择插入图片还是本地上传都可以
点击确认之后显示如下:
以上也支持再次更改视频封面。
音频上传
由于ueditor并没有提供音频上传功能,所以这里需要自己模仿视频上传来实现音频上传的功能。
修改ueditor.config.js文件,增加插入音频功能入口
//这个地方的toolbars其实是默认的full类型也就是全部的编辑器操作项 toolbars=[[...,'insertvideo','insertaudio', 'music',...]] //当鼠标放在工具栏上时显示的tooltip提示,留空支持自动多语言配置,否则以配置值为准 labelMap: {'insertaudio' : '音频', }
修改ueditor.all.js文件,增加插入音频页面和命令入口
//对话框路径,如果在ueditor.config.js配置了iframeUrlMap会被其覆盖 var iframeUrlMap = {...,'insertvideo':'~/dialogs/video/video.html','insertaudio':'~/dialogs/audio/audio.html', .... } //对话框按钮 var dialogBtns = {noOk:['searchreplace', 'help', 'spechars', 'webapp','preview'],ok:[...,'insertvideo','insertaudio',...] };
修改/DjangoUeditor/static/ueditor/lang/zh-cn/zh-cn.js文件,模仿insertvideo增加insertaudio的相关配置
'insertaudio':{'static':{'lang_tab_insertV':"插入音频",'lang_tab_searchV':"搜索音频",'lang_tab_uploadV':"上传音频",'lang_audio_url':"音频网址",'lang_audio_size':"音频尺寸",'lang_audioW':"宽度",'lang_audioH':"高度",'lang_alignment':"对齐方式",'audioSearchTxt':{'value':"请输入搜索关键字!"},'audioType':{'options':["全部", "热门", "娱乐", "搞笑", "体育", "科技", "综艺"]},'audioSearchBtn':{'value':"百度一下"},'audioSearchReset':{'value':"清空结果"},'lang_input_fileStatus':' 当前未上传文件','startUpload':{'style':"background:url(upload.png) no-repeat;"},'lang_upload_size':"音频尺寸",'lang_upload_width':"宽度",'lang_upload_height':"高度",'lang_upload_alignment':"对齐方式",'lang_format_advice':"建议使用mp3格式."},'numError':"请输入正确的数值,如123,400",'floatLeft':"左浮动",'floatRight':"右浮动",'"default"':"默认",'block':"独占一行",'urlError':"输入的音频地址有误,请检查后再试!",'loading':" 音频加载中,请等待……",'clickToSelect':"点击选中",'goToSource':'访问源音频','noAduio':" 抱歉,找不到对应的音频,请重试!",'browseFiles':'浏览文件','uploadSuccess':'上传成功!','delSuccessFile':'从成功队列中移除','delFailSaveFile':'移除保存失败文件','statusPrompt':' 个文件已上传! ','flashVersionError':'当前Flash版本过低,请更新FlashPlayer后重试!','flashLoadingError':'Flash加载失败!请检查路径或网络状态','fileUploadReady':'等待上传……','delUploadQueue':'从上传队列中移除','limitPrompt1':'单次不能选择超过','limitPrompt2':'个文件!请重新选择!','delFailFile':'移除失败文件','fileSizeLimit':'文件大小超出限制!','emptyFile':'空文件无法上传!','fileTypeError':'文件类型不允许!','unknownError':'未知错误!','fileUploading':'上传中,请等待……','cancelUpload':'取消上传','netError':'网络错误','failUpload':'上传失败!','serverIOError':'服务器IO错误!','noAuthority':'无权限!','fileNumLimit':'上传个数限制','failCheck':'验证失败,本次上传被跳过!','fileCanceling':'取消中,请等待……','stopUploading':'上传已停止……','uploadSelectFile':'点击选择文件','uploadAddFile':'继续添加','uploadStart':'开始上传','uploadPause':'暂停上传','uploadContinue':'继续上传','uploadRetry':'重试上传','uploadDelete':'删除','uploadTurnLeft':'向左旋转','uploadTurnRight':'向右旋转','uploadPreview':'预览中','updateStatusReady': '选中_个文件,共_KB。','updateStatusConfirm': '成功上传_个,_个失败','updateStatusFinish': '共_个(_KB),_个成功上传','updateStatusError': ',_张上传失败。','errorNotSupport': 'WebUploader 不支持您的浏览器!如果你使用的是IE浏览器,请尝试升级 flash 播放器。','errorLoadConfig': '后端配置项没有正常加载,上传插件不能正常使用!','errorExceedSize':'文件大小超出','errorFileType':'文件格式不允许','errorInterrupt':'文件传输中断','errorUploadRetry':'上传失败,请重试','errorHttp':'http请求错误','errorServerUpload':'服务器返回出错' },
修改/DjangoUeditor/settings.py文件,模仿insertvideo配置来增加insertaudio配置
# 上传音频配置 "audioActionName": "uploadaudio", # 执行上传视频的action名称 "audioPathFormat": "",#文件存储路径格式 "audioFieldName": "upfile", # 提交的视频表单名称 "audioMaxSize": 102400000, # 上传大小限制,单位B,默认100MB "audioUrlPrefix": "",#上传url前缀 "audioAllowFiles": [".mp3"], # 上传视频格式显示
修改/DjangoUeditor/static/ueditor/themes/default/css/ueditor.css,增加以下内容,我这里图标用的是ueditor自带的图标也就是音乐搜索的图标
/*音频上传*/ .edui-default .edui-for-insertaudio .edui-dialog-content {width: 590px;height: 390px; } .edui-default .edui-for-insertaudio .edui-icon {background-position: -18px -40px; }
修改/DjangoUeditor/static/ueditor/dialogs/audio/audio.css
其实就是复制一份video.css将video字眼替换成audio即可,下面只给出涉及到audio的相关css
#audioUrl {width: 490px;height: 21px;line-height: 21px;margin: 8px 5px;background: #FFF;border: 1px solid #d7d7d7; } #audioSearchTxt{margin-left:15px;background: #FFF;width:200px;height:21px;line-height:21px;border: 1px solid #d7d7d7;} #audioType{width: 65px;height: 23px;line-height: 22px;border: 1px solid #d7d7d7; } #audioSearchBtn,#audioSearchReset{/*width: 80px;*/height: 25px;line-height: 25px;background: #eee;border: 1px solid #d7d7d7;cursor: pointer;padding: 0 5px; } #preview .previewAudio {position:absolute;top:0;margin:0;padding:0;height:280px;width:100%;} #audioInfo {width: 120px;float: left;margin-left: 10px;_margin-left:7px;} #audioFloat div{cursor:pointer;opacity: 0.5;filter: alpha(opacity = 50);margin:9px;_margin:5px;width:38px;height:36px;float:left;} #audioFloat .focus{opacity: 1;filter: alpha(opacity = 100)} #uploadAudioInfo{margin-top:10px;float:right;padding-right:8px;}
增加/DjangoUeditor/static/ueditor/dialogs/audio/audio.html(按照video.html来改就行)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title></title><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/><script type="text/javascript" src="../internal.js"></script><link rel="stylesheet" type="text/css" href="audio.css" /> </head> <body> <div class="wrapper"><div id="audioTab"><div id="tabHeads" class="tabhead"><span tabSrc="audio" class="focus" data-content-id="audio"><var id="lang_tab_insertV"></var></span><span tabSrc="upload" data-content-id="upload"><var id="lang_tab_uploadV"></var></span></div><div id="tabBodys" class="tabbody"><div id="audio" class="panel focus"><table><tr><td><label for="audioUrl" class="url"><var id="lang_audio_url"></var></label></td><td><input id="audioUrl" type="text"></td></tr></table><div id="preview"></div><div id="audioInfo"><fieldset><legend><var id="lang_audio_size"></var></legend><table><tr><td><label for="audioWidth"><var id="lang_audioW"></var></label></td><td><input class="txt" id="audioWidth" type="text"/></td></tr><tr><td><label for="audioHeight"><var id="lang_audioH"></var></label></td><td><input class="txt" id="audioHeight" type="text"/></td></tr></table></fieldset><fieldset><legend><var id="lang_alignment"></var></legend><div id="audioFloat"></div></fieldset></div></div><div id="upload" class="panel"><div id="upload_left"><div id="queueList" class="queueList"><div class="statusBar element-invisible"><div class="progress"><span class="text">0%</span><span class="percentage"></span></div><div class="info"></div><div class="btns"><div id="filePickerBtn"></div><div class="uploadBtn"><var id="lang_start_upload"></var></div></div></div><div id="dndArea" class="placeholder"><div class="filePickerContainer"><div id="filePickerReady"></div></div></div><ul class="filelist element-invisible"><li id="filePickerBlock" class="filePickerBlock"></li></ul></div></div><div id="uploadAudioInfo"><fieldset><legend><var id="lang_upload_size"></var></legend><table><tr><td><label><var id="lang_upload_width"></var></label></td><td><input class="txt" id="upload_width" type="text"/></td></tr><tr><td><label><var id="lang_upload_height"></var></label></td><td><input class="txt" id="upload_height" type="text"/></td></tr></table></fieldset><fieldset><legend><var id="lang_upload_alignment"></var></legend><div id="upload_alignment"></div></fieldset></div></div></div></div> </div><!-- jquery --> <script type="text/javascript" src="../../third-party/jquery-1.10.2.min.js"></script><!-- webuploader --> <script type="text/javascript" src="../../third-party/webuploader/webuploader.min.js"></script> <link rel="stylesheet" type="text/css" href="../../third-party/webuploader/webuploader.css"><!-- audio --> <script type="text/javascript" src="audio.js"></script> </body> </html>
增加/DjangoUeditor/static/ueditor/dialogs/audio/audio.js,也是按照video.js来改就行
由于内容过长不方便贴出代码,具体代码可移步前往 我的博客下载完整源代码在/DjangoUeditor/static/ueditor/ueditor.all.js增加音频上传插件
//plugins/audio.js UE.plugins['insertaudio'] = function (){var me =this;/***** @param url 视频地址* @param width 视频宽度* @param height 视频高度* @param align 视频对齐* @param id id* @param align 音频对齐* @param classname class* @param type 类型(image还是video)*/function creatInsertStr(url,width,height,id,align,classname,type){var str="";switch(type){case 'image':str='<img '+(id ? 'id="' + id+'"' : '') +(align ? 'style="float:' + align + '"' : '') +' width="'+ width +'" height="' + height + '" _url="'+url+'" class="'+classname+'"' +' src="'+me.options.langPath+me.options.lang+'/images/music.png" />'break;case 'audio':str='<audio'+ ' class="'+classname+'" ' +(align ? 'style="float:' + align + '"' : '') +' controls preload="none" width="' + width + '" height="' + height +'" _url="'+url+'" src="' + url + '"></audio>';breakreturn str;}return str;}/**** @param root* @param img2audio 为true表示image转audio,为false表示audio转image*/function switchImgAndVideo(root,img2audio){utils.each(root.getNodesByTagName(img2audio ? 'img' : 'audio'),function(node){var className = node.getAttr('class');if(className && className.indexOf('fake-audio') != -1){var html = creatInsertStr(node.getAttr("_url"),node.getAttr('width'), node.getAttr('height'),null, node.getStyle("float"),className,img2audio?'audio':'image');node.parentNode.replaceChild(UE.uNode.createElement(html),node);}if(className && className.indexOf('upload-audio') != -1){var html = creatInsertStr(node.getAttr("_url"), node.getAttr('width'), node.getAttr('height'),null, node.getStyle("float"),className,img2audio?'audio':'image');node.parentNode.replaceChild(UE.uNode.createElement(html),node);}})}me.addOutputRule(function(root){switchImgAndVideo(root,true)});me.addInputRule(function(root){switchImgAndVideo(root)});me.commands["insertaudio"] = {/*** 插入视频* @command insertaudio* @method execCommand* @param { String } cmd 命令字符串* @param { Array } videoArr 需要插入的视频的数组, 其中的每一个元素都是一个键值对对象, 描述了一个视频的所有属性*/execCommand:function (cmd, audioObjs,type) {var me = this,audioObjs = utils.isArray(audioObjs)?audioObjs:[audioObjs];var html = [],id = 'tmpAudio', cl;for(var i=0,vi,len = audioObjs.length;i<len;i++){vi = audioObjs[i];cl = (type == 'upload' ? 'upload-audio audio-js vjs-default-skin':'fake-audio');html.push(creatInsertStr( vi.url, vi.width || 400, vi.height || 95, id + i, vi.align, cl, 'image'));}me.execCommand("inserthtml",html.join(""),true);var rng = this.selection.getRange();for(var i= 0,len=audioObjs.length;i<len;i++){var img = this.document.getElementById(id+i);domUtils.removeAttributes(img,'id');rng.selectNode(img).select();me.execCommand('imagefloat',audioObjs[i].align)}},/*** 查询当前光标所在处是否是一个视频* @command insertvideo* @method queryCommandState* @param { String } cmd 需要查询的命令字符串* @return { int } 如果当前光标所在处的元素是一个视频对象, 则返回1,否则返回0*/queryCommandState:function () {var me = this,img = me.selection.getRange().getClosedNode(),flag = img && (img.className == "faked-audio" || img.className.indexOf("upload-audio")!=-1);return flag ? 1 : 0;}}; };
具体效果如下,其实实现起来也不复杂,毕竟都是按照视频上传的代码来改下就行。
代码块
ueditor通过syntaxhighlighter高亮生成的代码html文件是这样的一个结构底部出现水平滚动条
<table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div> </td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="html spaces"> </code><code class="html plain"><</code><code class="html keyword">p</code> <code class="html color1">class</code><code class="html plain">=</code><code class="html string">"rollBlock"</code><code class="html plain">>这是一段长度很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长的文字</</code><code class="html keyword">p</code><code class="html plain">></code></div></div></td></tr></tbody>
</table>
```
PC端页面显示效果如下:
移动端页面显示效果如下:
可以看出代码并没有自动出现横向滚动条,导致代码语句超过了该内容所在区域,一开始我通过审查元素给对应class加上"overflow: auto
,发现并不行,后来就百度了下看看能不能找到解决的办法,后来在该ueditor解决syntaxhighlighter美化代码没有出现横向滚动条)找到了解决办法,我们可以通过修改shCore.js里面源码,位置在该js文件大概2266行,也就是该js生成上面代码的地方,给上面的代码再强行在table前加上,<div style="overflow-x: auto!important;"><table></table></div>
原代码内容如下:
html ='<div id="' + getHighlighterId(this.id) + '" class="' + classes.join(' ') + '">'+ (this.getParam('toolbar') ? sh.toolbar.getHtml(this) : '')+ '<table border="0" cellpadding="0" cellspacing="0">'+ this.getTitleHtml(this.getParam('title'))+ '<tbody>'+ '<tr>'+ (gutter ? '<td class="gutter">' + this.getLineNumbersHtml(code) + '</td>' : '')+ '<td class="code">'+ '<div class="container">'+ html+ '</div>'+ '</td>'+ '</tr>'+ '</tbody>'+ '</table>'+ '</div>';
修改后的代码如下:
html ='<div id="' + getHighlighterId(this.id) + '" class="' + classes.join(' ') + '">'+ (this.getParam('toolbar') ? sh.toolbar.getHtml(this) : '')+'<div style="overflow-x: auto!important;">'+ '<table border="0" cellpadding="0" cellspacing="0">'+ this.getTitleHtml(this.getParam('title'))+ '<tbody>'+ '<tr>'+ (gutter ? '<td class="gutter">' + this.getLineNumbersHtml(code) + '</td>' : '')+ '<td class="code">'+ '<div class="container">'+ html+ '</div>'+ '</td>'+ '</tr>'+ '</tbody>'+ '</table>'+ '</div>'+ '</div>'
;
最后让我们可以看下页面修改效果
ueditor编辑器二次开发与优化相关推荐
- 基于百度编辑器Ueditor的二次开发
基于百度编辑器Ueditor的二次开发 官网下载 基本配置 简化后端配置,不请求后端配置项 后端接口规范 修改图片上传 说明及修改 新增按钮及弹窗(自定义附件上传) 按钮文案修改 在业务开发的时候,曾 ...
- 实战-Ueditor扩展二次开发
第一部分 开发前期准备 1.UEditor从1.4.1开始,添加对于二次开发的扩展支持. Jeewx扩展二次开发采用1.4.3.1 Jsp 版本 2.上传图片设置 简述: UE做的不够灵活,不如老版 ...
- UEditor 如何进行二次开发
背景 UEditor虽然功能众多,但对于广大开发者来说,还是有很多定制化的功能需求,如果都靠UEditor团队自己开发那是不现实的,这时就需要广大开发者在UEditor的基础上自己开发定制功能.但在之 ...
- 基于PbootCMS二次开发版,集成常用二次开发功能
原文链接:基于PbootCMS二次开发版,集成常用二次开发功能 相关说明 基于PbootCMS二次开发,优化后台体验,集成常用功能 不涉及对原PbootCMS授权机制改动或破解,用户使用仍需遵守其相关 ...
- java web 轻量 编辑器_NKeditor: NKedtior是一款优秀的轻量级Web编辑器,基于 Kindedior 二次开发...
再一次温馨提示:建议有问题请提 issue 不要在评论区提, 评论区的内容一般没有及时看就被其他消息掩盖了,很容易被忽略看不到. NKeditor NKedtior是基于 kindeditor 进行二 ...
- ueditor html显示图片,百度ueditor编辑器上传图片后img标签的title、alt属性优化简单方法...
<百度ueditor编辑器上传图片后img标签的title.alt属性优化简单方法>要点: 本文介绍了百度ueditor编辑器上传图片后img标签的title.alt属性优化简单方法,希望 ...
- 软件工程专业(互联网应用开发与优化方向)软件工程实践二环节教学大纲
软件工程专业(互联网应用开发与优化方向)软件工程实践二环节教学大纲 培训课程 Phthon Web开发 实训公司 XXX 总周数 3周
- 像MIUI一样做Zabbix二次开发(5)——那些坑和优化方向
踩过的那些坑 从2011年开始玩Zabbix,踩过的坑着实不少,被研发的同事吐了无数槽,所谓"情到深度又爱又恨".以下简述印象比较深刻的几个坑: 二次开发的方式:2011刚开始做的 ...
- Markdown网页编辑器集成,stackedit二次开发,公式编辑器
网页编辑器,stackedit二次开发,在线公式编辑器支持kindeditor.stackedit,段落缩进2个字符,设置字体种颜色.字体背景颜色.
- OceanBase 二次开发 之 Kunpeng + openEuler 适配优化(一)
引子 由于时间和精力的原因,上一篇关于OceanBase二次开发的帖子Hello OceanBase!开启OB二次开发之后就很少在社区活动了.当然,还是要感谢社区小编和运营们不失时机的提醒与督促_.这 ...
最新文章
- 贺州学院计算机协会,2019年广西高等教育学会数学教学专业委员会年会暨学术交流会在贺州学院召开...
- 技术17期:近几年崛起的Pytorch究竟是何方神圣?
- Factory模式与Prototype模式的异同
- bubbliiiing/keras-face-recognition
- OneNote2016安装代码高亮插件-NoteHightlight
- [HAOI2006]受欢迎的牛
- Dx11DemoBase 基类(二) 初始化 DirectX11 的 4个基本步骤
- RedisRDB持久化机制
- ExtJs 带分页的comboBox
- 一进庙会freeeim
- 【OpenCV】SIFT原理与源码分析
- spark学习-54-Spark RDD的clean()方法
- 多线程调用同一个对象的方法_这一次,让我们完全掌握Java多线程(2/10)
- ionic 性能优化
- DirectX 下载地址
- BT.656标准简介
- 基于javaweb学生就业管理系统的设计与实现(论文+程序设计+数据库文件)下载
- 【WiFi】WiFi 2.4G信道国家码对应关系
- MySQL高性能:索引、锁、事务、分库分表如何撑起亿级数据
- 关闭/开启“此电脑”左边的导航栏win10
热门文章
- 985大学计算机专业学费贵吗,一本大学的学费一般是多少?5000左右够吗?985学姐告诉你!...
- Mysql命令大全——转自博客园 宁静.致远博客
- 基于51单片机自行车码表霍尔测速里程显示超速报警方案原理图设计
- 有关龙的成语(词语)、故事、诗歌
- 切片函数python_python切片操作
- 两个ip linux,教你ipconfig有两个ip地址的解决方法
- 成功入园啦~ BoomShakalaka
- 示波器的带宽与采样率是什么关系
- 专访Riverbed CEO:私有化和出售业务瘦身后的Riverbed更专注
- day 46 http和html