From cc545f1d917c92b17d7723028ff0a54eb0f3765a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org>
Date: Thu, 2 Feb 2023 08:46:48 +0100
Subject: [PATCH] Add markup TextareaWithPreview widget

---
 .../_hx_textarea_widget_value_processed.html  | 13 ++++++++++++
 .../forms/widgets/textarea_with_preview.html  | 15 ++++++++++++++
 scipost_django/markup/urls.py                 |  1 +
 scipost_django/markup/views.py                | 20 ++++++++++++++++++-
 scipost_django/markup/widgets.py              | 19 ++++++++++++++++++
 5 files changed, 67 insertions(+), 1 deletion(-)
 create mode 100644 scipost_django/markup/templates/markup/forms/widgets/_hx_textarea_widget_value_processed.html
 create mode 100644 scipost_django/markup/templates/markup/forms/widgets/textarea_with_preview.html
 create mode 100644 scipost_django/markup/widgets.py

diff --git a/scipost_django/markup/templates/markup/forms/widgets/_hx_textarea_widget_value_processed.html b/scipost_django/markup/templates/markup/forms/widgets/_hx_textarea_widget_value_processed.html
new file mode 100644
index 000000000..e01f6d97d
--- /dev/null
+++ b/scipost_django/markup/templates/markup/forms/widgets/_hx_textarea_widget_value_processed.html
@@ -0,0 +1,13 @@
+<div style="border: 2px solid orange;">
+  <div style="margin: 1rem;">
+    <strong>Preview</strong>&nbsp;<em>(detected language: {{ markup.language }}</em>)
+    {% if markup.errors %}
+      <span style="text-color: red;">Errors: {{ markup.errors }}</span>
+    {% endif %}
+    {% if markup.warnings %}
+      <span style="text-color: orange;">Errors: {{ markup.warnings }}</span>
+    {% endif %}
+  </div>
+  <hr>
+  <div style="margin: 1rem;">{{ markup.processed|safe }}</div>
+</div>
diff --git a/scipost_django/markup/templates/markup/forms/widgets/textarea_with_preview.html b/scipost_django/markup/templates/markup/forms/widgets/textarea_with_preview.html
new file mode 100644
index 000000000..c5c703c70
--- /dev/null
+++ b/scipost_django/markup/templates/markup/forms/widgets/textarea_with_preview.html
@@ -0,0 +1,15 @@
+<div hx-post="{% url 'markup:_hx_process' field=widget.name %}"
+     hx-params="csrfmiddlewaretoken, {{ widget.name }}"
+     hx-target="#markup-preview-{{ widget.attrs.id }}"
+     hx-trigger="load, keyup from:#{{ widget.attrs.id }} delay:500ms"
+     hx-confirm="unset"
+>
+</div>
+
+<div id="markup-preview-{{ widget.attrs.id }}"
+     style="margin-bottom: 1rem;"
+></div>
+
+<textarea name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>
+  {% if widget.value %}{{ widget.value }}{% endif %}
+</textarea>
diff --git a/scipost_django/markup/urls.py b/scipost_django/markup/urls.py
index 4043bf479..ca01ada17 100644
--- a/scipost_django/markup/urls.py
+++ b/scipost_django/markup/urls.py
@@ -10,6 +10,7 @@ app_name = "markup"
 
 urlpatterns = [
     path("process/", views.process, name="process"),
+    path("_hx_process/<str:field>", views._hx_process, name="_hx_process"),
     path("help/", views.markup_help, name="help"),
     path("help/plaintext", views.plaintext_help, name="plaintext_help"),
     path("help/Markdown", views.markdown_help, name="markdown_help"),
diff --git a/scipost_django/markup/views.py b/scipost_django/markup/views.py
index 92a6f2663..e61daa531 100644
--- a/scipost_django/markup/views.py
+++ b/scipost_django/markup/views.py
@@ -3,7 +3,7 @@ __license__ = "AGPL v3"
 
 
 from django.contrib.auth.decorators import login_required
-from django.http import JsonResponse
+from django.http import HttpResponse, JsonResponse
 from django.shortcuts import render
 
 from .constants import (
@@ -33,6 +33,24 @@ def process(request):
     return JsonResponse({})
 
 
+@login_required
+def _hx_process(request, field):
+    """
+    API call to process the POSTed text in given for field. Returns an HTML snippet.
+    """
+    if request.method == "POST":
+        data = request.POST.copy()
+        data["markup_text"] = request.POST.get(field, None)
+        form = MarkupTextForm(data)
+        if form.is_valid():
+            return render(
+                request,
+                "markup/forms/widgets/_hx_textarea_widget_value_processed.html",
+                context = { "markup": form.get_processed_markup(),},
+            )
+    return HttpResponse()
+
+
 def markup_help(request):
     """
     General help page about markup facilities at SciPost.
diff --git a/scipost_django/markup/widgets.py b/scipost_django/markup/widgets.py
new file mode 100644
index 000000000..2cc73918f
--- /dev/null
+++ b/scipost_django/markup/widgets.py
@@ -0,0 +1,19 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.forms.widgets import Textarea
+
+from .utils import process_markup
+
+
+class TextareaWithPreview(Textarea):
+    template_name = 'markup/forms/widgets/textarea_with_preview.html'
+
+    def get_context(self, name, value, attrs):
+        context = super().get_context(name, value, attrs)
+        context["value_processed"] = process_markup(
+            context["widget"]["value"],
+            include_errors=True,
+        )
+        return context
-- 
GitLab