fix: live preview honors source_format — RST/HTML/mediawiki now render correctly

The /preview-post endpoint hardcoded markdown_to_html(), ignoring the
node's source_format. RST pages showed `..` comments verbatim, literal
`name_` references, and unrendered `.. _target: url` definitions, even
though Node.set_data dispatched correctly on save. Preview lied; save
told the truth.

Mirror set_data's dispatch in preview_post:
  - markdown → markdown_to_html (unchanged)
  - html     → pandoc clean → markdown_to_html (matches set_data)
  - any other → pandoc + namespace sanitizer

Plumb source_format from the edit textarea via data-source-format,
read by sendPreview in custom.js, sent as a form param.
This commit is contained in:
russell@unturf.com 2026-06-05 20:26:39 -04:00
parent 1527ef7d64
commit 64a15b6a86
No known key found for this signature in database
3 changed files with 33 additions and 6 deletions

View file

@ -80,9 +80,14 @@ function previewAjax(textarea, div, show_raw, mathjax) {
function sendPreview(textarea, div, mathjax) {
var url = '/preview-post';
var ta = document.getElementById(textarea);
var data = new FormData();
data.append('data', document.getElementById(textarea).value);
data.append('data', ta.value);
data.append('csrf_token', csrf_token);
// textarea declares its source_format via data-source-format; the
// endpoint dispatches to pandoc for rst/html/mediawiki/latex when set.
var fmt = ta.dataset.sourceFormat;
if (fmt) data.append('source_format', fmt);
fetch(url, {
method: 'POST',

View file

@ -76,6 +76,7 @@
name = "thread_data"
id = "edit-textarea-{{ node.id }}"
class = "common-textarea textarea_edit"
data-source-format = "{{ node.source_format or 'markdown' }}"
onkeyup = "previewAjax( 'edit-textarea-{{ node.id }}', 'node-data-{{ node.id }}', show_raw=false, mathjax={{ request.mathjax }} )"
placeholder = "{% if request.namespace.placeholder_text %}{{ request.namespace.placeholder_text }}{% else %}What do you want to say? markdown{% endif %}"
required>{{ node.data }}</textarea>

View file

@ -54,12 +54,33 @@ def redirect_to_root(request):
# This ajax endpoint should work whether a user is authenticated or not.
@view_config(route_name="preview-post", renderer="string", xhr=True, require_csrf=False)
def preview_post(request):
"""AJAJ: Accept MarkDown data param, return HTML"""
"""AJAJ: Accept data + optional source_format, return HTML.
Mirrors Node.set_data dispatch so the live preview matches what the
save path will produce. Without this, RST / HTML / mediawiki / latex
nodes silently fell through markdown rendering & previews lied
e.g. an RST file showed `..` comments + literal `name_` references
instead of resolved hyperlinks.
"""
data = request.params.get("data", "")
source_format = (request.params.get("source_format") or "markdown").strip().lower()
try:
return markdown_to_html(request.params["data"], request.namespace,
dbsession=request.dbsession)
except:
return "we could not create markdown to html preview."
if source_format in ("", "markdown"):
return markdown_to_html(data, request.namespace, dbsession=request.dbsession)
if source_format == "html":
# match set_data: clean HTML through markdown pipeline
from remarkbox.lib.pandoc import convert
cleaned = convert(data, from_format="html", to_format="markdown")
return markdown_to_html(cleaned, request.namespace, dbsession=request.dbsession)
# pandoc handles rst, mediawiki, latex, org, etc.
from remarkbox.lib.pandoc import convert
from remarkbox.lib.render import make_cleaner_from_namespace
from remarkbox.lib.sanitize_html import clean_raw_html
html = convert(data, from_format=source_format, to_format="html5",
standalone=False)
return clean_raw_html(html, make_cleaner_from_namespace(request.namespace))
except Exception:
return "we could not create a preview for source_format=%s." % source_format
@view_config(route_name="favicon")