Markdown编辑器——Editor.MD于Flask:
能预览的Markdown编辑器中, 读狗书时用的
Flask-Pagedown
比较不错, 在逛知乎的时候学习greyli大神的flask富文本编辑器实现,实践中遇到 Editor.md很合胃口, 类似简书或者 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(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文件。
这里我们将其保存下来,以便归档查看以及预览方便节省资源。如果正文渲染的话还是建议用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 :
<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的回调已经完成了。在下篇里我会谈一下图片上传的问题。
个人是新入门的求职学生,欢迎大家指教