基于Flask的Markdown编辑器实践

Markdown编辑器——Editor.MD于Flask:

能预览的Markdown编辑器中, 读狗书时用的Flask-Pagedown比较不错, 在逛知乎的时候学习greyli大神的flask富文本编辑器实现,实践中遇到 Editor.md很合胃口, 类似简书或者 Remarkable的左右分栏预览方式非常喜欢,见坑就跳吧。

最终效果大概是这样的:

11⁄22⁄18_7.png

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(style="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文件。

11⁄22⁄18_1.png

这里我们将其保存下来,以便归档查看以及预览方便节省资源。如果正文渲染的话还是建议用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的渲染表单:

11⁄22⁄18_2.png

渲染后:


11⁄22⁄18_3.png

再对比编辑栏效果:

11⁄22⁄18.png

在文章预览处我们做相应的修改,
_post.html :

<h3 class=`text-primary`><a href=`{{ url_for('.show_post', post_id=post.id) }}`>{{ post.title }}</a></h3>
    <p>
        <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>
    </p>

先调用safe转义过滤器, 再调用striptags清除html渲染后的格式, 最后调用truncate过滤器只保留开头255个字符,而后惯例一个Read More链接.

如果使用了Flask-Migrate的Alembic话,创建迁移环境生成迁移脚本更新数据库三部曲即可。由于数据库已经从SQlite迁移到了MySQL, 一切都没什么。生产环境还是先备份以下


目前来说Markdown于Flask的实现应该是打好了基础. Editor.md的界面比较讨喜, 相比其他富文本编辑器更加受青睐. 关于Editor.md的进阶功能还有许多, 日后需要还会继续添加.至此,Editor.MD的回调已经完成了。在下篇里我会谈一下图片上传的问题。

个人是新入门的求职学生,欢迎大家指教

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容