Skip to content

Commit

Permalink
Render alerts in Bootstrap 5 (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
dyve committed Mar 16, 2021
1 parent fb53cd4 commit c8312e0
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 37 deletions.
32 changes: 15 additions & 17 deletions src/django_bootstrap5/components.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
from django.utils.safestring import mark_safe
from django.utils.html import format_html
from django.utils.translation import gettext as _

from .css import merge_css_classes
from .html import render_tag
from .text import text_value

ALERT_TYPES = ["primary", "secondary", "succes", "danger", "warning", "info", "light", "dark"]

def render_alert(content, alert_type=None, dismissible=True):

def render_alert(content, alert_type="info", dismissible=True):
"""Render a Bootstrap alert."""
button = ""
if not alert_type:
alert_type = "info"
css_classes = ["alert", "alert-" + text_value(alert_type)]
if alert_type not in ALERT_TYPES:
raise ValueError(f"Value {alert_type} is not a valid alert type. Please choose from {', '.join(ALERT_TYPES)}.")
css_classes = [f"alert alert-{alert_type}"]
if dismissible:
css_classes.append("alert-dismissible")
css_classes.append("alert-dismissible fade show")
close = _("close")
button = (
'<button type="button" class="close" data-dismiss="alert" aria-label="{close}">&times;</button>'
).format(close=close)
button_placeholder = "__BUTTON__"
return mark_safe(
render_tag(
"div",
attrs={"class": " ".join(css_classes), "role": "alert"},
content=mark_safe(button_placeholder) + text_value(content),
).replace(button_placeholder, button)
button = f'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="{close}"></button>'
css_classes = merge_css_classes(*css_classes)
return render_tag(
"div",
attrs={"class": css_classes, "role": "alert"},
content=format_html("{content}" + button, content=content),
)
40 changes: 40 additions & 0 deletions tests/test_bootstrap_alert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from django.test import TestCase

from .test_templates import render_template_with_bootstrap


class BootstrapAlertTest(TestCase):
def test_bootstrap_alert(self):
self.assertEqual(
render_template_with_bootstrap('{% bootstrap_alert "content" dismissible=False %}'),
'<div class="alert alert-info" role="alert">content</div>',
)

def test_bootstrap_alert_dismissible(self):
self.assertHTMLEqual(
render_template_with_bootstrap('{% bootstrap_alert "content" %}'),
(
'<div class="alert alert-info alert-dismissible fade show" role="alert">'
"content"
'<button aria-label="close" class="btn-close" data-bs-dismiss="alert" type="button">'
"</div>"
),
)

def test_bootstrap_alert_html_content(self):
self.assertEqual(
render_template_with_bootstrap('{% bootstrap_alert "foo<br>bar" dismissible=False %}'),
'<div class="alert alert-info" role="alert">foo<br>bar</div>',
)
self.assertEqual(
render_template_with_bootstrap(
"{% bootstrap_alert value dismissible=False %}", context={"value": "foo<br>bar"}
),
'<div class="alert alert-info" role="alert">foo&lt;br&gt;bar</div>',
)
self.assertEqual(
render_template_with_bootstrap(
"{% bootstrap_alert value|safe dismissible=False %}", context={"value": "foo<br>bar"}
),
'<div class="alert alert-info" role="alert">foo<br>bar</div>',
)
19 changes: 11 additions & 8 deletions tests/test_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@


class AlertsTest(TestCase):
CLOSE = '<button aria-label="close" class="btn-close" data-bs-dismiss="alert" type="button">'

def test_render_alert_without_type(self):
self.assertEqual(
render_alert("content"),
(
'<div class="alert alert-info alert-dismissible" role="alert">'
'<button type="button" class="close" data-dismiss="alert" aria-label="close">&times;</button>content'
'<div class="alert alert-info alert-dismissible fade show" role="alert">'
"content"
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>'
"</div>"
),
)
Expand All @@ -21,9 +24,9 @@ def test_render_alert_with_type(self):
self.assertEqual(
render_alert("content", alert_type="danger"),
(
'<div class="alert alert-danger alert-dismissible" role="alert">'
'<button type="button" class="close" data-dismiss="alert" aria-label="close">&times;</button>'
'<div class="alert alert-danger alert-dismissible fade show" role="alert">'
"content"
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>'
"</div>"
),
)
Expand All @@ -32,9 +35,9 @@ def test_render_alert_with_safe_content(self):
self.assertEqual(
render_alert(mark_safe('This is <a href="https://example.com" class="alert-link">a safe link</a>!')),
(
'<div class="alert alert-info alert-dismissible" role="alert">'
'<button type="button" class="close" data-dismiss="alert" aria-label="close">&times;</button>'
'<div class="alert alert-info alert-dismissible fade show" role="alert">'
'This is <a href="https://example.com" class="alert-link">a safe link</a>!'
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>'
"</div>"
),
)
Expand All @@ -43,9 +46,9 @@ def test_render_alert_with_unsafe_content(self):
self.assertEqual(
render_alert("This is <b>unsafe</b>!"),
(
'<div class="alert alert-info alert-dismissible" role="alert">'
'<button type="button" class="close" data-dismiss="alert" aria-label="close">&times;</button>'
'<div class="alert alert-info alert-dismissible fade show" role="alert">'
"This is &lt;b&gt;unsafe&lt;/b&gt;!"
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>'
"</div>"
),
)
Expand Down
12 changes: 0 additions & 12 deletions tests/test_templatetags.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,18 +471,6 @@ def test_attributes_consistency(self):
self.assertEqual(attrs, form.fields["addon"].widget.attrs)


class ComponentsTest(TestCase):
def test_bootstrap_alert(self):
res = render_template_with_form('{% bootstrap_alert "content" alert_type="danger" %}')
self.assertEqual(
res.strip(),
'<div class="alert alert-danger alert-dismissible" role="alert">'
+ '<button type="button" class="close" data-dismiss="alert" '
+ 'aria-label="close">'
+ "&times;</button>content</div>",
)


class MessagesTest(TestCase):
def test_bootstrap_messages(self):
class FakeMessage(object):
Expand Down

0 comments on commit c8312e0

Please sign in to comment.