diff --git a/manuscript/admin.py b/manuscript/admin.py index 3da6c13..0bfd7ad 100644 --- a/manuscript/admin.py +++ b/manuscript/admin.py @@ -653,7 +653,7 @@ class FolioAdmin(ImportExportModelAdmin): }, ), ("Toponyms", {"fields": ("toponym_list",)}), - ("Notes", {"fields": ("folio_includes_map", "folio_notes")}), + ("Notes", {"fields": ("folio_includes_map", "folio_notes", "public_note")}), ) def get_fieldsets(self, request, obj=None): @@ -664,7 +664,10 @@ def get_fieldsets(self, request, obj=None): "Line Range", {"fields": ("line_code_range_start", "line_code_range_end")}, ), - ("Notes", {"fields": ("folio_includes_map", "folio_notes")}), + ( + "Notes", + {"fields": ("folio_includes_map", "folio_notes", "public_note")}, + ), ) return self.fieldsets diff --git a/manuscript/migrations/0129_add_public_notes.py b/manuscript/migrations/0129_add_public_notes.py new file mode 100644 index 0000000..5ae4501 --- /dev/null +++ b/manuscript/migrations/0129_add_public_notes.py @@ -0,0 +1,32 @@ +# Generated by Django 5.1.15 on 2026-11-03 17:46 + +import prose.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("manuscript", "0128_folio_iiif_canvas"), + ] + + operations = [ + migrations.AddField( + model_name="folio", + name="public_note", + field=prose.fields.RichTextField( + blank=True, + help_text="Shown to readers where this folio begins in the text.", + null=True, + ), + ), + migrations.AddField( + model_name="singlemanuscript", + name="public_note", + field=prose.fields.RichTextField( + blank=True, + help_text="Shown to readers at the start of the text.", + null=True, + ), + ), + ] diff --git a/manuscript/models.py b/manuscript/models.py index b680332..ba478aa 100644 --- a/manuscript/models.py +++ b/manuscript/models.py @@ -620,6 +620,11 @@ class Folio(models.Model): validators=[validate_line_number_code], ) folio_notes = RichTextField(blank=True, null=True) + public_note = RichTextField( + blank=True, + null=True, + help_text="Shown to readers where this folio begins in the text.", + ) manuscript = models.ForeignKey( "SingleManuscript", on_delete=models.CASCADE, blank=True, null=True ) @@ -715,6 +720,11 @@ class SingleManuscript(models.Model): help_text="The URL to the IIIF manifest for the manuscript. If there isn't one, leave blank.", verbose_name="IIIF URL", ) + public_note = RichTextField( + blank=True, + null=True, + help_text="Shown to readers at the start of the text.", + ) gazetteer_url = models.URLField( max_length=255, blank=True, diff --git a/manuscript/templatetags/stanza_tags.py b/manuscript/templatetags/stanza_tags.py index c110426..5ca07b2 100644 --- a/manuscript/templatetags/stanza_tags.py +++ b/manuscript/templatetags/stanza_tags.py @@ -78,6 +78,12 @@ def annotate_text(html_content, annotations): return mark_safe("".join(result)) +@register.filter +def has_text(html): + """Whether rich text has any text, since an emptied editor can leave markup""" + return bool(html and BeautifulSoup(html, "html.parser").get_text(strip=True)) + + @register.filter def format_ms(manuscript): """Format manuscripts for dropdowns as: diff --git a/manuscript/tests.py b/manuscript/tests.py index e080854..c3c6f83 100644 --- a/manuscript/tests.py +++ b/manuscript/tests.py @@ -789,6 +789,52 @@ def test_folio_holding_only_the_stanza_number(self): self.assertEqual(self.stanza_dividers(response), [("01.01.00", "1v")]) self.assertEqual(self.line_breaks(response), [("01.01.01", "2r")]) + def test_shows_a_folio_s_public_note_at_a_divider(self): + self.add_folios(("1r", "01.01.00", "01.02.08"), ("1v", "01.03.00", "01.04.08")) + Folio.objects.filter(folio_number="1v").update( + public_note="