热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Web实战之Markdown编辑器

前言由于想在自己的页面里嵌入markdown编辑器,搜了不少现成的,感觉都不是很满意:–EpicEditor:太丑,代码不高亮,没有工具栏–Bootstrap-Markdown:不

前言

由于想在自己的页面里嵌入markdown编辑器,搜了不少现成的,感觉都不是很满意:
– EpicEditor:太丑,代码不高亮,没有工具栏
– Bootstrap-Markdown:不能多行代码,没有实时预览
– PageDown:不能多行代码,使用不方便
– zepto(没记错的话):太重,是一个框架

所以萌生了自己写一个的想法

文档和Demo,快点我

提供的功能

  • 工具栏
  • 多行代码与高亮
  • 快捷键
  • 两种模式——实时效果和按键预览
  • 两种调用方法–手动添加类名和异步加载
  • Tab缩进
  • 没有全屏编辑和自动保存

依赖的第三方工具

  • highlight.js
  • marked.js
  • jquery
  • bootstrap(基本主题需要,并非必要)

代码

Javascript/**
*
* Created by suemi on 14-12-5.
*/
var SuMarkdown=function(option){
var load=function(mark){
var get=function(dst){
var result={};
$(dst).each(function(i,e){
result.select=(
// Mozilla, Webkit
('selectionStart' in e && function()
{
var l = e.selectionEnd - e.selectionStart;
return {
start: e.selectionStart,
end: e.selectionEnd,
length: l,
text: e.value.substr(e.selectionStart, l)
};
}) ||
// Internet Explorer
(document.selection && function()
{
e.focus();
var r = document.selection.createRange();
if (r === null)
{
return {
start: 0,
end: e.value.length,
length: 0
};
}
var re = e.createTextRange();
var rc = re.duplicate();
re.moveToBookmark(r.getBookmark());
rc.setEndPoint('EndToStart', re);
return {
start: rc.text.length,
end: rc.text.length + r.text.length,
length: r.text.length,
text: r.text
};
}) ||
// Not supported
function()
{
return null;
}
)();
if(result.select) {
result.cOntainer=$(this);
return false;
}
else return true;
});
return result;
};
var replace= function (target,text,option){
var tmp;
$(target).each(function(i,e){
tmp=(
// Mozilla, Webkit
('selectionStart' in e && function()
{
var start = e.selectionStart;
e.value = e.value.substr(0, e.selectionStart) + text + e.value.substr(e.selectionEnd, e.value.length);
if (option === true || option === undefined)
{
e.selectiOnStart= start;
e.selectiOnEnd= start + text.length;
}
else
{
e.selectiOnStart= e.selectiOnEnd= start + text.length;
}
return $(e);
}) ||
// Internet Explorer
(document.selection && function()
{
e.focus();
document.selection.createRange().text = text;
return $(e);
}) ||
// Not supported
function()
{
e.value += text;
return $(e);
}
)();
if(tmp) return false;
else return true;
});
return tmp;
};
var methods={
bold:function(){
var reg=/^\*{2}[^\0]*\*{2}$/m;
var target=get($('textarea',mark));
var dst;
if(!reg.test(target.select.text))
dst=replace(target.container,'**'+target.select.text+'**');
else dst=replace(target.container,target.select.text.split('**')[1]);
return dst;
},
italic:function(){
var reg=/^_[^\0]*_$/m;
var target=get($('textarea',mark));
var dst;
if(!reg.test(target.select.text))
dst=replace(target.container,'_'+target.select.text+'_');
else dst=replace(target.container,target.select.text.split('_')[1]);
return dst;
},
head:function(){
var reg=/^#{1,6}[^\0]*/m;
var target=get($('textarea',mark));
var dst;
if(!reg.test(target.select.text))
dst=replace(target.container,'###'+target.select.text);
else dst=replace(target.container,target.select.text.split(/#{1,6}/)[1]);
return dst;
},
link:function(){
var reg=/^\[[^\0]*\]\([^\0]*\)$/m;
var target=get($('textarea',mark));
var dst;
if(!reg.test(target.select.text)) {
var url=prompt('Enter your URL :');
if(!url) return target.container;
if(target.select.text=='') target.select.text="Enter your link description here:";
dst = replace(target.container, '[ ' + target.select.text + ' ](' + url + ')');
}
else dst=replace(target.container,target.select.text.split('[')[1].split(']')[0]);
return dst;
},
img:function(){
var reg=/^!\[[^\0]*\]\([^\0]*\)$/m;
var target=get($('textarea',mark));
var dst;
if(!reg.test(target.select.text)) {
var url=prompt('Enter your Image URL :');
if(!url) return target.container;
if(target.select.text=='') target.select.text="Enter your image description here:";
dst = replace(target.container, '![ ' + target.select.text + ' ](' + url + ')');
}
else dst=replace(target.container,target.select.text.split('[')[1].split(']')[0]);
return dst;
},
list:function(){
var target=get($('textarea',mark));
if(target.select.text=='') target.select.text='list text here';
var dst=replace(target.container,'- '+target.select.text);
return dst;
},
orderlist:function(){
var target=get($('textarea',mark));
if(target.select.text=='') target.select.text='list text here';
var dst=replace(target.container,'1. '+target.select.text);
return dst;
},
code:function(){
var reg=/^`[^\0]*`$/m;
var target=get($('textarea',mark));
var dst;
if(target.select.text=='') target.select.text='list text here';
if(!reg.test(target.select.text))
dst=replace(target.container,'`'+target.select.text+'`');
else dst=replace(target.container,target.select.text.split('`')[1]);
return dst;
},
block:function(){
var target=get($('textarea',mark));
if(target.select.text=='') target.select.text='quote here';
var dst=replace(target.container,'> '+target.select.text);
return dst;
},
tab:function(){
var target=get($('textarea',mark));
var dst=replace(target.container,' ' +target.select.text.split('\n').join('\n '),false);
return dst;
},
preview:function(event){
var blank=$('.suPreview',mark);
var state=blank.css('display');
var target=get($('textarea',mark));
if(state=='none'){
blank.html(marked(target.container.val()));
$('pre code',blank).each(function(i,block){
hljs.highlightBlock(block);
});
$('.suEditor',mark).css('display','none');
blank.css('display','block');
}
else{
blank.css('display','none');
$('.suEditor',mark).css('display','block');
target.container.focus();
}
}
};
//set the hotkey
$('textarea',mark).attr('data-state','0').on('keyup',function(event){
if(event.keyCode==17) $(this).attr('data-state','0');
});
$('textarea:input',mark).on('keydown',function(event){
var dst,tmp;
switch(event.keyCode){
case 9:
event.preventDefault();
dst=methods.tab();
break;
case 17:
$(this).attr('data-state','1');
break;
case 66:
tmp=$(this).attr('data-state');
if(tmp=='1') {
methods.bold();
event.preventDefault();
}
break;
case 73:
tmp=$(this).attr('data-state');
if(tmp=='1') {
methods.italic();
event.preventDefault();
}
break;
case 71:
tmp=$(this).attr('data-state');
if(tmp=='1') {
methods.img();
event.preventDefault();
}
break;
case 72:
tmp=$(this).attr('data-state');
if(tmp=='1') {
methods.head();
event.preventDefault();
}
break;
case 75:
tmp=$(this).attr('data-state');
if(tmp=='1') {
methods.code();
event.preventDefault();
}
break;
case 76:
tmp=$(this).attr('data-state');
if(tmp=='1') {
methods.link();
event.preventDefault();
}
break;
case 79:
tmp=$(this).attr('data-state');
if(tmp=='1') {
methods.orderlist();
event.preventDefault();
}
break;
case 81:
tmp=$(this).attr('data-state');
if(tmp=='1') {
methods.block();
event.preventDefault();
}
break;
case 85:
tmp=$(this).attr('data-state');
if(tmp=='1') {
methods.list();
event.preventDefault();
}
break;
default : break;
}
});
$('.su-toolbar > *',mark).each(function(i,element){
var str=$(this).attr('class');
str=str.split(/\s+/g);
for(var i in str){
if(str[i].substring(0,8)=='su-tool-'){
var method=str[i].substring(8);
if(method=='preview') break;
$(this).on('click',function(event){
event.preventDefault();
var dst=methods[method]();
if(option.preview)
$('.suPreview',mark).html(marked(dst.val()));
dst.focus();
});
}
}
return true;
});
if(!option.clean){
$('.suPreview',mark).css({
"width":"50%",
"float":"left",
'overflow': 'auto',
'padding': '0 20px',
});
$('.suEditor',mark).css({
"width":"50%",
"float":"left",
"display":"block"
});
$('textarea',mark).css({
"tab-size":"4",
"padding":"20px",
"resize":"none",
"overflow":"auto"
});
$('textarea:focus',mark).css('background','#fff');
}
if(option.preview){
$('.su-tool-preview',mark).attr('disabled','true');
$('.suEditor textarea',mark).on('keyup',function(){
$('.suPreview',mark).html(marked($(this).val()));
$('pre code',mark).each(function(i,block){
hljs.highlightBlock(block);
});
});
}
else{
$('.suPreview',mark).css({
'width':"100%",
'display':'none',
"border-left":"solid 1px",
"border-color": $('textarea',mark).css('border-color')
});
$('.suEditor',mark).css({width:"100%"});
$('.su-tool-preview',mark).on('click',function(){
methods.preview();
});
}
if(option.css) mark.css(option.css);
if(option.textCss) $('.textarea',mark).css(option.textCss);
if(option.previewCss) $('.suPreview',mark).css(option.previewCss);
if(option.textHeight){
$('textarea',mark).css('height',option.textHeight);
$('.suPreview',mark).css('height',option.textHeight);
}
};
if(!option.target) option.target=$('.suMarkdown');
if(!option.insert){
var mark=option.target;
console.log($('textarea',mark).css('height'));
load(option.target);
}
else{
$.get(option.baseUrl,function(data){
mark=$("

");
mark.html(data);
load(mark);
$(option.target).append(mark);
},'html');
}
};

使用时

Javascript$(function(){
var option={
target:'.suMarkdown',
preview:true,
};
SuMarkdown(option);
});

为了便于理解,附上基本模板的代码

html



































推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了10分钟了解Android的事件分发相关的知识,希望对你有一定的参考价值。什么是事件分发?大家 ... [详细]
  • Thisissuewasoriginallyopenedbyashashicorp/terraform#5664.Itwasmigratedhe ... [详细]
  • 我正在使用ChemDoodleWebComponents在网页上显示分子。基本上,我可以在我的页面中插入以下脚本,它将创建一个HTML5canvas元素来显示分子。vartrans ... [详细]
  • html css在线便宜,在线HTML、CSS和JS工具汇总
    本文提供了在线HTML、CSS和JS工具汇总,它们都是直接在浏览器上可以使用的在线工具,基本上都是比较简单操作的,只适合简单的调试工作&# ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • Android native层服务例子Bp和Bn
    转入android阵地,被各种权限所阻挠,app写个jni各种没有权限,只能开个native服务,本来android的服务& ... [详细]
  • RMarkdown是一种用于在R中生成可重复生成的报告的开源工具。它可以帮助您将所有代码,结果和编写都放在一个地方,并以有吸引力且易于消化的方式格式化所 ... [详细]
  • 之前我曾经写过一篇关于CSS的border-image属性的文章。现在几乎所有的现代浏览器都支持这个属性——除了IE10及以下IE版本。看起来这是一个非常 ... [详细]
author-avatar
灰灰t2502911555
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有