本身動手開發更好用的markdown編輯器-07(擴展語法)

這裏文章都是從我的的github博客直接複製過來的,排版可能有點亂. 原始地址  http://benq.im/2015/05/19/hexomd-07/
 
文章目錄
  1. 1. 準備工做
  2. 2. 目錄語法
  3. 3. emojis表情語法
    1. 3.1. 準備表情素材
    2. 3.2. 實現功能
  4. 4. 編輯器語法高亮
  5. 5. 總結
  6. 6. 附件

上一篇咱們實現了自動更新的功能.css

在前面的6篇中,咱們基本沒作什麼創造,都只是像玩樂高那樣把零件拼接成咱們想要的東西.
今天這篇將對marked進行簡單擴展, 增長咱們的markdown編輯器支持的語法,實現目錄,emojis表情兩種新語法.
以及改造codemirror,實現咱們自定義語法的編輯器高亮顯示(這個原本是要放到下一篇,可是剛剛作完後發現內容很短,因此就又合併到這篇裏來了).html

對於不想看如何實現的朋友,直接下載v0.6.0.2,而後點擊右上角的更新按鈕更新到最新版便可.git

準備工做

首先打開marked,Fork一份到本身倉庫. 對marked的改造都將基於咱們的這個fork版本.
github

目錄語法

功能描述: 自動提取全部H標籤,造成目錄樹,在解析markdown文本時,若是遇到[TOC]標籤則自動將其替換爲目錄.markdown

將咱們fork的版本clone到本地,打開lib/marked.js.全部代碼都在這個文件裏.hexo

修改inline.gfm,增長目錄語法匹配正則app

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* GFM Inline Grammar
*/


inline.gfm = merge({}, inline.normal, {
escape: replace(inline.escape)('])', '~|])')(),
url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,

del: /^~~(?=\S)([\s\S]*?\S)~~/,
toc: /\s*\[TOC\]/,
text: replace(inline.text)
(']|', '~]|')
('|', '|https?://|')
()
});

 

修改Renderer,增長toctocItem兩個方法,用於生成目錄標籤:編輯器

1
2
3
4
5
6
7
8
9
10
Renderer.prototype.toc = function (items) {
var html = '<div id="toc" class="toc"><ul class="toc-tree">';
html += items;
html += '</ul></div>';
return html;
}

Renderer.prototype.tocItem = function (id, level, text) {
return '<li class="toc-item toc-level-' + level + '"><a class="toc-link" href="#' + id + '"><span class="toc-number"></span> <span class="toc-text">' + text + '</span></a></li>';
};

 

修改Rendererheading方法,爲其賦予id做爲點擊目錄項的錨點oop

1
2
3
4
5
6
7
8
9
Renderer.prototype.heading = function(text, level, raw) {
var escapedText = text.toLowerCase();
return '<h' + level + '><a name="' +
escapedText +
'" class="anchor" href="#' +
escapedText +
'"><span class="header-link"></span></a>' +
text + '</h' + level + '>';
};

 

修改 Parser.prototype.parse,在解析時預生成好目錄標籤備用:優化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Parse Loop
*/


Parser.prototype.parse = function (src) {
var me = this, tocItems = '';
//預生成好目錄標籤
src.forEach(function (token) {
if (token.type == 'heading') {
id = token.text.toLowerCase();
tocItems += me.renderer.tocItem(id, token.depth, token.text);
}
});
this.inline = new InlineLexer(src.links, this.options, this.renderer);
this.inline.tocHTML = me.renderer.toc(tocItems);

this.tokens = src.reverse();

var out = '';
while (this.next()) {
out += this.tok();
}

return out;
};

 

最後是修改InlineLexer,在匹配到[TOC]時將其替換爲完整的目錄標籤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Lexing/Compiling
*/


InlineLexer.prototype.output = function(src) {
var out = ''
, link
, text
, href
, cap;
while (src) {
//toc語法
if (cap = this.rules.toc.exec(src)) {
src = src.substring(cap[0].length);
out += this.tocHTML;
continue;
}
...
}

 

這樣目錄語法就完成了,沒幾行代碼,效果如圖(預覽的樣式比較醜,這系列的某一篇會專門優化預覽樣式):

emojis表情語法

準備表情素材

我將要實現的emoji表情庫基於http://www.emoji-cheat-sheet.com/這個項目,你們能夠經過這個頁面查看全部表情的命名.
我將這裏全部表情上傳一份到個人七牛空間裏,這樣訪問會快一些.

實現功能

emojis語法的實現跟目錄相似.

修改inline.gfm,增長emojis語法匹配正則

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* GFM Inline Grammar
*/


inline.gfm = merge({}, inline.normal, {
escape: replace(inline.escape)('])', '~|])')(),
url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,

del: /^~~(?=\S)([\s\S]*?\S)~~/,
emoji: /^:([A-Za-z0-9_\-\+]+?):/,
toc: /\s*\[TOC\]/,
text: replace(inline.text)
(']|', ':~]|')
('|', '|https?://|')
()
});

 

Renderer增長emoji方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Renderer.prototype.emoji = function (emoji) {
//圖片使用本身的七牛空間
return '<img src="'
+ 'http://7xj6bw.com1.z0.glb.clouddn.com/'

+ encodeURIComponent(emoji)
+ '.png"'
+ ' alt=":'

+ escape(emoji)
+ ':"'
+ ' title=":'

+ escape(emoji)
+ ':"'
+ ' class="emoji" align="absmiddle" height="20" width="20">';
};

 

最後,在InlineLexer裏:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Lexing/Compiling
*/


InlineLexer.prototype.output = function(src) {
var out = ''
, link
, text
, href
, cap;
while (src) {
...
// emoji (gfm)
if (cap = this.rules.emoji.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.emoji(cap[1]);
continue;
}
...
}

 

完成!這個功能比目錄功能更加簡單

編輯器語法高亮

這裏就再也不去fork codemirror這個項目了,有興趣的能夠去fork,修改完後提交給官方.
咱們直接簡單粗暴的修改lib/codemirror/mode/markdown/markdown.js.

增長toc和emoji的正則:

1
2
3
4
5
6
7
8
9
10
11
12
13
...
, toc = 'toc'
, emoji = 'emoji'
..
..
var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
, ulRE = /^[*\-+]\s+/
, olRE = /^[0-9]+\.\s+/
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
, atxHeaderRE = /^#+/
, tocRE = /\[TOC\]/
, emojiRE = /^:([A-Za-z0-9_\-\+]+?):/
..

 

blockNormal方法裏爲匹配到的標籤返回獨立的class:

1
2
3
4
5
6
7
...
} else if(match = stream.match(tocRE)){
return toc;
} else if(match = stream.match(emojiRE)){
return emoji;
}
...

 

這樣就搞定了,編輯器會爲匹配到的代碼加上相應的class


有了,class,就能夠在樣式修改自定義語法的高亮顯示了,好比我如今用的樣式文件mdn-like
打開這個樣式文件,加上樣式:

1
2
3
4
5
6
.cm-toc{
background:#ccc;
}

.cm-emoji{
color:#F7A21B;
}

 

如今這些語法在編輯器裏有獨特的高亮效果了:

總結

經過兩個自定義語法的實現,咱們能夠總結出自定義語法的通常步驟:

  1. 增長語法關鍵詞的匹配正則.
  2. Renderer裏增長相應的標籤生成方法.
  3. InlineLexer裏處理匹配到的語法.

接下來的計劃:

  1. 導出pdf,html文件.
  2. 美化預覽樣式.

附件

v0.6.0.2
項目地址

相關文章
相關標籤/搜索