From 3f73a824231cfb364da15cdd04861335aca4b065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org> Date: Sun, 5 Feb 2023 15:17:37 +0100 Subject: [PATCH] Improve user info for TextareaWithPreview widget --- scipost_django/forums/forms.py | 2 + scipost_django/markup/constants.py | 7 ++++ .../_hx_textarea_widget_value_processed.html | 6 +-- scipost_django/markup/utils.py | 40 +++++++++++++++---- scipost_django/profiles/views.py | 2 +- 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/scipost_django/forums/forms.py b/scipost_django/forums/forms.py index 5ee198234..b732ca425 100644 --- a/scipost_django/forums/forms.py +++ b/scipost_django/forums/forms.py @@ -61,6 +61,8 @@ class MeetingForm(ForumForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.fields["preamble"].widget = TextareaWithPreview() + self.fields["minutes"].widget = TextareaWithPreview() if self.instance: self.fields["parent"].initial = self.instance.parent diff --git a/scipost_django/markup/constants.py b/scipost_django/markup/constants.py index 4be31e14b..ad4fa9761 100644 --- a/scipost_django/markup/constants.py +++ b/scipost_django/markup/constants.py @@ -2,6 +2,13 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" +recognized_markup_languages = { + "plain": "plain", + "md": "Markdown", + "reST": "reStructuredText", +} + + # Dictionary for regex expressions to recognize reStructuredText headers. # This follows the Python conventions: order is #, *, =, -, ", ^ and # for the first two levels (# and *), over- and underlining are necessary, while 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 index 4f5534230..7c3d2cc43 100644 --- 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 @@ -1,12 +1,12 @@ <div style="border: 2px solid orange; padding: 0.5rem;"> <span style="padding: 0.5rem; background-color: #f3f6ff; color: #004057;"> - <em><strong>Preview</strong> (detected language: <strong>{{ markup.language }}</strong></em>) + <em><strong>Preview</strong> (markup language: <strong>{{ markup.language }}</strong></em>) </span> {% if markup.errors %} - <span style="text-color: red;">Errors: {{ markup.errors }}</span> +  <span style="color: red;">Errors: {{ markup.errors }}</span> {% endif %} {% if markup.warnings %} - <span style="text-color: orange;">Errors: {{ markup.warnings }}</span> +  <span style="color: orange;">Warnings: {{ markup.warnings }}</span> {% endif %} <div style="margin: 1rem;">{{ markup.processed|safe }}</div> </div> diff --git a/scipost_django/markup/utils.py b/scipost_django/markup/utils.py index d40017faa..4db7bb008 100644 --- a/scipost_django/markup/utils.py +++ b/scipost_django/markup/utils.py @@ -13,6 +13,7 @@ from django.utils.encoding import force_text from django.utils.safestring import mark_safe from .constants import ( + recognized_markup_languages, ReST_HEADER_REGEX_DICT, ReST_ROLES, ReST_DIRECTIVES, @@ -375,7 +376,7 @@ def apply_markdown_preserving_displayed_maths(text): ) -def process_markup(text, language_forced=None, include_errors=False): +def process_markup(text_given, language_forced=None, include_errors=False): """ Process a text in a markup language into HTML. @@ -385,16 +386,40 @@ def process_markup(text, language_forced=None, include_errors=False): Parameters: * `language_forced=None`: override language auto-detection """ - markup_detector = detect_markup_language(text) markup = {"language": "plain", "errors": None, "warnings": None, "processed": ""} - if language_forced and language_forced != markup_detector["language"]: + if not text_given: + return markup + + # See if text_given contains a language coerce + coerced = False + if text_given.partition("\n")[0].startswith("#coerce:"): + language_requested_code = text_given.partition("\n")[0].partition("#coerce:")[2] + coerced = True + text = text_given.partition("\n")[2] + if language_requested_code not in recognized_markup_languages: + markup["errors"] = ( + f"Unknown language ({language_requested_code}) requested for coerce.\n" + "Your options are: " + f"{recognized_markup_languages}\n" + "To coerce, at the start of the first line, write #coerce:[code] " + "with the language code, e.g. #coerce:reST" + ) + return markup + language_requested = recognized_markup_languages[language_requested_code] + markup["warnings"] = f"Coercing language: {language_requested}" + else: + text = text_given + + markup_detector = detect_markup_language(text) + + if coerced and language_requested != markup_detector["language"]: markup["warnings"] = ( - "Warning: markup language was forced to %s, while the detected one was %s." - ) % (language_forced, markup_detector["language"]) + "markup language was coerced to %s, while the detected one was %s." + ) % (language_requested, markup_detector["language"]) - language = language_forced if language_forced else markup_detector["language"] + language = language_requested if coerced else markup_detector["language"] markup["language"] = language markup["errors"] = markup_detector["errors"] @@ -409,7 +434,8 @@ def process_markup(text, language_forced=None, include_errors=False): "%s</span><br><br>" ) % linebreaksbr(markup["errors"]) markup["processed"] = mark_safe(error_msg + linebreaksbr(text)) - return markup + if not coerced: + return markup if language == "reStructuredText": warnStream = StringIO() diff --git a/scipost_django/profiles/views.py b/scipost_django/profiles/views.py index b82026056..113a72382 100644 --- a/scipost_django/profiles/views.py +++ b/scipost_django/profiles/views.py @@ -358,7 +358,7 @@ def _hx_profile_dynsel_list(request): @permission_required("scipost.can_create_profiles") def _hx_profile_specialties(request, profile_id): """ -Returns a snippet with current and possible specialties, with one-click actions. + Returns a snippet with current and possible specialties, with one-click actions. """ profile = get_object_or_404(Profile, pk=profile_id) if request.method == "POST": -- GitLab