Flask-PageDown: Markdown Editor Extension for Flask-WTF

Posted by
on under

(I can't help it. I keep coming up with ideas for cool Flask extensions.)

If you've asked or answered a question on Stack Overflow you have seen the editor that they use. You type your text using Markdown syntax in a standard text area HTML control and below it a preview is generated as you type. This editor is powered by an open source project called PageDown.

Today I'm introducing Flask-PageDown, a wrapper extension that makes it really easy to add this control to your Flask-WTF based forms.

Demo

Below is a an example that will give you an idea of what this extension can do in your own application. Type Markdown in the text editor below and see how it gets converted on the fly to HTML!

Installation & Configuration

You can install the extension with pip:

$ pip install flask-pagedown

The extension needs to be initialized after the application instance is created:

from flask_pagedown import PageDown

app = Flask(__name__)
pagedown = PageDown(app)

You can also use the init_app(app) format.

The Editor is supported via two Javascript files. To include these files in your HTML document you have to call pagedown.html_head() from inside the <head> element of your page:

<html>
    <head>
    {{ pagedown.html_head() }}
    </head>
    <body>
    ...
    </body>
</html>

The Javascript files are loaded from a CDN, the files do not need to be hosted by your application. If you prefer to host these files locally then replace the html_head() call with your own <script> tags for files Markdown.Converter.js and Markdown.Sanitizer.js (or their minified versions).

Creating a Form with a PageDown Field

The extension exports a PageDownField class that works exactly like a TextAreaField. Here is an example form that uses this field:

from flask_wtf import Form
from flask_pagedown.fields import PageDownField
from wtforms.fields import SubmitField

class PageDownFormExample(Form):
    pagedown = PageDownField('Enter your markdown')
    submit = SubmitField('Submit')

The field can be rendered to a template in the usual way. For example:

    <form method="POST">
        {{ form.pagedown(rows = 10) }}
        {{ form.submit }}
    </form>

The preview element does not need to be added, the extension does that for you.

Note that when a form with a PageDownField is submitted the raw Markdown text is submitted. The form does not receive the HTML preview. If you need to store the HTML in the server then you should use a server-side Markdown converter like Flask-Markdown.

Styles

You can define custom styles for the text area and preview elements. The text area can be referenced with the flask-pagedown-input CSS class. The CSS class for the preview is flask-pagedown-preview.

Feedback and Contributions Accepted

As always I look forward to your comments and suggestions. Please write below in the comments.

At this time the extension does not display a toolbar like the one on Stack Overflow. I will probably add that in a future release, but if you get to it first please send me a pull request on github.

Miguel

Become a Patron!

Hello, and thank you for visiting my blog! If you enjoyed this article, please consider supporting my work on this blog on Patreon!

38 comments
  • #1 cancerballs said

    Thanks for all the Flask tutorials!

    Would you consider writing a tutorial about writing an extension for Flask?

  • #2 Miguel Grinberg said

    @cancerballs: Not a bad idea...

  • #3 mg said

    You're flask articles are always awesome and since you like flask extensions so much, could you publish an article about developing a simple flask extension from start to finish? It would be awesome!

  • #4 mlsn said

    Hey Miguel,
    I'm using Flask-Pagedown on my blog and it works like a charm!
    But it would be nice if there was a way to separate the preview from the editor. That would make styling your forms much easier.

    Keep up the good work!

  • #5 Miguel Grinberg said

    @mlsn: the preview div is assigned a "flask-pagedown-preview" CSS class. Is that insufficient for your needs?

  • #6 mlsn said

    @Miguel: Yeah, i know. I can live with it but it would be nice if i could add some HTML between the editor and the preview.

  • #7 Deepsys9 said

    Hi Miguel,

    Please keep creating these extensions! They are great, as is your overall series.

    I have an app based on your Flask book running at Heroku and I turned on SSL support. The browsers (Chrome, Firefox) block references to non-http content resources used by bootstrap, moment and pagedown.
    I was able to set BOOTSTRAP_CDN_PREFER_SSL to force flask-bootstrap to point to content over https.

    Is there a similar config option for resources used markdown convertor and flask moment?

    'http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.3.1/moment-with-langs.min.js'
    'http://cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Converter.min.js

    Thanks!

  • #8 Miguel Grinberg said

    @Deepsys9: This is an oversight on my part, I need to document the use of the SSL option in Flask-Bootstrap and also add similar options to my extensions Flask-Moment and Flask-PageDown. In the meantime, you can add explicity <script> tags that reference the SSL version of the libs, but I will add SSL to the extensions.

    Side note: you are probably one of very few people who already made it to the end of the book, and you have clearly found a real problem that I need to address. If you have found other problems, as minor as they may seem to you, please let me know, I have to be all over the place so some little things are bound to slip through so I hope early release readers like you will help with catching all of these.

    And thanks for your nice review, by the way.

  • #9 Luca Barbato said

    Do you happen to know if there is already a markdown implementation for python that doesn't lack? Had been months I'm trying to get moin-2 to render properly some extendend markdown the normal python implementation is supposed to grok but exports not as a proper element tree. I'm tempted to complete my port of kramdown to python...

  • #10 David H Hagan said

    Do you have any recomendations/tutorials on how to render the markdown? I have unsuccessfully tried to using flask-markdown.

  • #11 progerz said

    Respect! Just amazing articles about Flask....
    I start to love Flask and writing my first website using that framework!

  • #12 Miguel Grinberg said

    @David: Flask-Markdown is old and out of date. The two options I have tried are markdown and markdown2. You can install both with pip.

  • #13 Horia said

    Hi Miguel,
    I'm having trouble with Pygments in your Talks app. It would be great if you can point me in the right direction.
    Thanks!
    Horia

  • #14 Miguel Grinberg said

    @Horia: I need more details, I don't recall having used Pygments in that application.

  • #15 yassine said

    Thanks for all the Flask tutorials!

  • #16 luna said

    Hi Miguel,You develop this extension is very good, but I want to add a toolbar and some shortcuts, studied the two days have been unsuccessful, you teach the way of thinking. Thank you very much!

  • #17 Miguel Grinberg said

    @luna: you probably need to look into client-side development with Javascript, Bootstrap, and jQuery. There isn't really much on the Flask server-side for what you want to do.

  • #18 luna said

    @Miguel,I see what you mean, but I'm a beginner just learning python, no more time to learn the javascript, jquery and bootstrap. So I want to ask you, is there any quick way to achieve.

  • #19 Miguel Grinberg said

    @luna: only if somebody else does the work for you.

  • #20 mannaia said

    @Miguel I was trying without success to combine MathJax and Pagedown. Basically no preview of the maths does show up, while regular text is perfectly working. Would you have any idea how to tackle the problem ?

    Thanks for the brillant tutorial.

  • #21 Miguel Grinberg said

    @mannaia: Did you look in the Javascript console for errors? Maybe that will give you a clue.

  • #22 Michael said

    @Miguel Thanks for putting this together. I'd like to use this as an viewer/editor of simple json configuration data on a web interface. Is there a good example for how I might pre-load a text file into the PageDown window?

  • #23 Miguel Grinberg said

    @Michael: The markdown field is compatible with the text area field from Flask-WTF. The example in the github repository sets some initial text if you want to see how it is done: https://github.com/miguelgrinberg/Flask-PageDown/blob/master/example/app.py.

  • #24 Michael said

    Perfect, This is simple but just what I need for now. Thanks

  • #25 ella sherilyn ramos said

    Hi Miguel,

    Great tutorial.

    What if I want to save the markdown text to database? Should I just save it as raw text (stringfield)? Then I need to retrieve that markdown and then render it to the user?

    Hope my question is clear!

    Thanks!

Leave a Comment