Day 30 Dev Notes
I did some searching online today, looking for a Markdown editor that I could easily embed in a page, so that I could provide a better editing experience for posts. But while I was searching, I had an idea - what if I just built a Markdown previewer alongside a regular textarea
element.
So I gave it a quick go, and it worked!
I had to make a bunch of changes to get this working, but ultimately it boils down to a view that takes a POST
request, and converts the content it receives into Markdown. This is rendered with a simple template that either displays error text or the rendered HTML content.
The view is fairly simple:
def preview_markdown(request: HttpRequest) -> HttpResponse:
"""View for the preview markdown page."""
html = ""
error = ""
if request.method == "POST" and "content" in request.POST:
try:
html = render_markdown(request.POST["content"])
except Exception as e:
msg = f"Error rendering markdown: {e}"
logger.exception(msg)
error = msg
return render(
request,
"djpress_admin/preview_markdown.html",
{"html": html, "error": error},
)
I went to the effort of error handling, but right now I don't know how to trigger an error, since the Markdown renderer faithfully converts just about any garbage I give it. I will probably add some tag sanitizing in the future, so the error handling will come in useful then. But right now, the Markdown rendering is fairly simple:
import markdown
from django.conf import settings
md = markdown.Markdown(extensions=settings.MARKDOWN_EXTENSIONS, output_format="html")
def render_markdown(markdown_text: str) -> str:
"""Return the Markdown text as HTML."""
html = md.convert(markdown_text)
md.reset()
return html
That will render just about anything you give it. Including <script>
tags and all sorts of JavaScript!
And of course, the most important component in the puzzle, is the amazing HTMX. I attached all the HTMX logic to the preview button, and this works great.
<button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-post="{% url "djpress_admin:preview_markdown" %}"
hx-params="content"
hx-target="#preview"
type="button"
class="btn btn-success">
Preview content
</button>
It's far from perfect, but for a quick and dirty demo, this worked amazingly well. I did this all in a new app called djpress_admin
, which as the name suggests will be an optional package that can be used to add some admin views to manage DJPress content.
Screenshot: