美文网首页Flask实践
基于Flask的Markdown编辑器实践

基于Flask的Markdown编辑器实践

作者: hallucigenia | 来源:发表于2018-11-25 21:12 被阅读2次

    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的回调已经完成了。在下篇里我会谈一下图片上传的问题。

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

    相关文章

      网友评论

        本文标题:基于Flask的Markdown编辑器实践

        本文链接:https://www.haomeiwen.com/subject/yrsmqqtx.html