基於Flask的Markdown編輯器實踐
Markdown編輯器——Editor.MD於Flask
能預覽的Markdown編輯器中, 讀狗書時用的Flask-Pagedown是真的簡單又還不錯, 在逛知乎的時候學習greyli大神的flask富文本編輯器實現,實踐中遇到 Editor.md很合胃口, Markdown所見即所得。類似簡書或者 Remarkable的左右分欄預覽方式非常喜歡,見坑就跳吧。
最終效果大概是這樣的:

Editor.md是個國人維護的開源項目, 四年沒更新不過還是很好用的。相關Issues比較多,基本上小問題翻翻即可解決,
首先進入Editor.md官網下載zip,或者點擊Github download下載
解壓重命名為editormd,並置入static文件夾
表單類里使用Flask-WTF設置<textarea>標籤存放文章內容, 定義TextAreaField欄位, 對Body欄位進行修改:
~forms.py:~
from wtforms import TextAreaField
#...
class PostForm(FlaskForm):
#...
body = TextAreaField(Body, [DataRequired()])
#...
此時編輯模板的js腳本, 用於拾取id=editormd的 textarea 渲染的
這真的是一個坑大的決定,相關探究並無太多參考,Editor.MD已經荒廢四年,相關文檔都未必打得開,基本都是Java做後端,Flask上幾乎沒人用。相關討論比較雜亂,甚至有的錯漏百出。基本只能靠踩坑和閱讀源碼來運作。目前還在艱苦奮鬥階段,有能力後會編寫相關拓展。
為便於支持更多的MarkDown格式甚至emoji代碼高亮表格解析等問題。而不是一點點自定義,這次我們利用更強大的Editor.MD編輯自帶的Markdown2HTML渲染方式。
new_post.html:
<link rel="stylesheet" href="{{ url_for(static,filename=editormd/css/editormd.css) }}"/>
這裡我將Editor.MD置於static靜態文件目錄並重命名為editormd,個人根據目錄自行更改即可。
使用saveHTMLToTextarea : true欄位開啟自動轉換HTML為後台直接提取html文檔提供介面。其中js代碼處注意寬度設置與Bootstrap4的body相衝突,這裡我們注釋掉width欄位,否則將無法直接提取html。如果是繼承模板,引入js較多時,可以在js的順序上優先保證editor.MD,上下文在最後繼承
new_post.html:
<script src="{{ url_for(static,filename=editormd/examples/js/jquery.min.js) }}"></script>
<script src="{{ url_for(static,filename=editormd/editormd.min.js) }}"></script>
<script type="text/javascript">
$(function () {
editormd("fancy-editormd", {
// width: "100%", 請不要添加
height: 640,
syncScrolling: "single",
path: "{{ url_for(static,filename=editormd/lib/) }}",
saveHTMLToTextarea : true
});
});
</script>
{{ super() }}
結尾scripts段載入JS:順序為jQuery在前, editormd.min.js在後.
相關的textarea部分 new_post.html:
<div id="fancy-editormd" class="editormd">
{{ form.body(stylex="display:none;") }}
</div>
在編輯文章的部分也照做即可。 其中的"fancy-editormd"欄位是自定義的,用於拾取textarea 這裡有個坑,如果使用WTForms渲染表單的話name屬性是無法更改的,而editormd理論上是通過name=「fancy-editormd-markdown-doc"屬性來渲染我們編輯markdown文件的地方 這裡不用擔心太多,如果沒有多個textarea的話,其實我們只需要照常渲染formbody即可,再次渲染時可見Editor.MD會自動找到第一個textarea並渲染為markdown編輯器,並自動為我們生成了一個textareaname=」fancy-editormd-html-code"裡面內容即是Editor.MD的HTML文件。

這裡我們將其保存下來,以便歸檔查看以及預覽方便節省資源。如果正文渲染的話還是建議用markdown即時轉換這樣表格和特殊內容更加直觀,當然如果伺服器並發訪問過多的話並不建議這麼做。
首先在Forms中我們自定義一個body_html用於保存撰寫文檔時Editor.MD留下的HTML格式文檔: forms.py:
class PostForm(FlaskForm):
#...
body_html = HiddenField()
添加一個實例化資料庫模型欄位的Column類在文章模型中,注意如果使用Flask-Whooshee全文搜索的話建立索引欄位改為我們的html格式文檔,還好注意而後使用reindex()方法重建索引。(目前文檔較少做了搜索也沒用,而後會單獨列出文章做詳細討論):
models.py:
@whooshee.register_model(title, body_html)
class Post(db.Model):
#...
body_html = db.Column(db.Text)
在文章管理藍本中直接使用request來獲取數據,不使用WTForms
admin.py:
from flask import request
# ...
@admin_bp.route(/post/new, methods=[GET, POST])
@login_required
def new_post():
if form.validate_on_submit():
# ...
body_html = request.form[fancy-editormd-html-code]
post = Post(..., body_html = body_html)
#...
同樣在編輯文章的藍本中也要做相應的修改:
@admin_bp.route(/post/<int:post_id>/edit, methods=[GET, POST])
@login_required
def edit_post(post_id):
# ...
if form.validate_on_submit():
# ...
post.body_html = request.form[fancy-editormd-html-code]
# ...
# ...
form.body_html.data = post.body_html
# ...
此時我們要編輯的都編輯完了,在文檔正部直接調用轉換好的html即可,加個safe過濾器即可 {{ post.body_html| safe }} 當然代碼高亮以及表格支持這些等等,想要顯示出編輯時右邊的預覽的效果,還是需要調用Editor.MD的渲染,在文章正文的模板里做相應的修改: 引入靜態文件,
<link href="{{ url_for(static, filename=editormd/css/editormd.preview.min.css) }}" rel="stylesheet" />
<link href="{{ url_for(static, filename=editormd/css/editormd.css) }}" rel="stylesheet" />
<!--以下是js部分 -->
<script type="text/javascript" src="{{ url_for(static, filename=editormd/lib/marked.min.js) }}"></script>
<script type="text/javascript" src="{{ url_for(static, filename=editormd/lib/prettify.min.js) }}"></script>
<script type="text/javascript" src="{{ url_for(static, filename=editormd/editormd.min.js) }}"></script>
<script type="text/javascript">
editormd.markdownToHTML("fancy-content");
</script>
在文檔中定義我們自定義的fancy-content
<div class="content" id="fancy-content">
{{ post.body_html| safe }}
</div>
這裡無需使用post原文,無需定義textarea,直接用flask-WTF的定義表單即可,直接使用html文件即可。
沒有引入Editor.MD的渲染表單:

渲染後:

再對比編輯欄效果:

在文章預覽處我們做相應的修改, _post.html :
# ...
<div class=post-body>
{% if post.body_html %}
{{ post.body_html |safe|striptags|truncate }}
{% else %}
{{ post.body }}
{% endif %}
</div>
<small><a href="{{ url_for(.show_post, post_id=post.id) }}">Read More</a></small>
#...
先調用safe轉義過濾器, 再調用striptags清除html渲染後的格式, 最後調用truncate過濾器只保留開頭255個字元,而後好用的來個Read More鏈接.
如果使用了Flask-Migrate的Alembic話,創建遷移環境生成遷移腳本更新資料庫三部曲即可。由於資料庫已經從SQlite遷移到了MySQL, 一切都沒什麼。生產環境還是先備份以下
目前來說Markdown於Flask的實現應該是打好了基礎. Editor.md的界面比較討喜, 相比其他富文本編輯器更加受青睞. 關於Editor.md的進階功能還有許多, 日後需要還會繼續添加.至此,Editor.MD的回調已經完成了。在下篇里我會談一下個人實踐圖片上傳的問題。
個人是新入門的求職中的學生,遇到問題歡迎大家指教
推薦閱讀:
