Skip to content

Commit

Permalink
Use the start tag's name for </dj-block> if possible.
Browse files Browse the repository at this point in the history
  • Loading branch information
adamghill committed Nov 9, 2024
1 parent b907c95 commit acd5254
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 14 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
**`base.html`**

```html
<dj-block name='content'>
</dj-block name='content'>
<dj-block name='content'> <!-- {% block content %} -->
</dj-block> <!-- {% endblock content %} -->
```

**`index.html`**
Expand Down Expand Up @@ -59,7 +59,7 @@

<dj-image src='img/django.jpg' /> <!-- <img src="{% static 'img/django.jpg' %}" /> -->
<dj-css href='css/styles.css' /> <!-- <link href="{% static 'css/styles.css' %}" rel="stylesheet" /> -->
</dj-block name='content'> <!-- {% endblock content %} -->
</dj-block> <!-- {% endblock content %} -->
```

**partial.html**
Expand Down
6 changes: 3 additions & 3 deletions docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
**`base.html`**

```
<dj-block name='content'>
</dj-block name='content'>
<dj-block name='content'> <!-- {% block content %} -->
</dj-block> <!-- {% endblock content %} -->
```

**`index.html`**
Expand Down Expand Up @@ -52,7 +52,7 @@
<dj-image src='img/django.jpg' /> <!-- <img src="{% static 'img/django.jpg' %}" /> -->
<dj-css href='css/styles.css' /> <!-- <link href="{% static 'css/styles.css' %}" rel="stylesheet" /> -->
</dj-block name='content'> <!-- {% endblock content %} -->
</dj-block> <!-- {% endblock content %} -->
```

**partial.html**
Expand Down
6 changes: 5 additions & 1 deletion docs/source/tag-elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@

## [`block`](https://docs.djangoproject.com/en/stable/ref/templates/builtins/#block)

```{note}
The end tag can optionally have a name attribute. If it is missing, the `endblock` will use the name attribute from the start tag.
```

```
<dj-block name='content'>
...
</dj-block name='content'>
</dj-block>
```

```html
Expand Down
57 changes: 50 additions & 7 deletions src/dj_angles/mappers/django.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from typing import TYPE_CHECKING

from dj_angles.exceptions import MissingAttributeError
from dj_angles.exceptions import InvalidEndTagError, MissingAttributeError
from dj_angles.mappers.utils import get_attribute_value_or_first_key
from dj_angles.strings import dequotify

Expand Down Expand Up @@ -60,27 +60,70 @@ def map_css(tag: "Tag") -> str:
return f'<link href="{{% static {href} %}}" {tag.attributes} />'


def map_endblock(tag: "Tag") -> str:
"""Mapper function for endblock tags. Not included in the default mappers and only called by `map_block`.
Args:
param tag: The tag to map.
"""

name = None

try:
name = get_attribute_value_or_first_key(tag, "name")

# Check that the end tag name is the same as the start tag's name
if tag.start_tag:
tag.start_tag.parse_attributes()

try:
start_name = get_attribute_value_or_first_key(tag.start_tag, "name")

if name != start_name:
raise InvalidEndTagError(tag, tag.start_tag)
except MissingAttributeError:
pass

except MissingAttributeError:
pass

if not name and tag.start_tag:
# Re-parse start tag attributes since it can empty from the previous parsing
tag.start_tag.parse_attributes()

try:
name = get_attribute_value_or_first_key(tag.start_tag, "name")
except MissingAttributeError:
pass

if name:
# The block tag doesn't actually want/need quoted strings per se, so remove them
name = dequotify(name)

return f"{{% endblock {name} %}}"

return "{% endblock %}"


def map_block(tag: "Tag") -> str:
"""Mapper function for block tags.
Args:
param tag: The tag to map.
"""

if tag.is_end:
return map_endblock(tag)

if not tag.attributes:
raise Exception("Missing block name")

django_template_tag = "block"

if tag.is_end:
django_template_tag = "endblock"

name = get_attribute_value_or_first_key(tag, "name")

# The block tag doesn't actually want/need quoted strings per se, so remove them
name = dequotify(name)

return f"{{% {django_template_tag} {name} %}}"
return f"{{% block {name} %}}"


def map_extends(tag: "Tag") -> str:
Expand Down
5 changes: 5 additions & 0 deletions src/dj_angles/mappers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
def get_attribute_value_or_first_key(tag: "Tag", attribute_name: str) -> str:
"""Gets the first attribute key or the first value for a particular attribute name.
As a side effect of this function, if the attribute is found, it will be removed from
`tag.attributes` because almost always that is the desired behavior. `tag.parse_attributes()`
can be called for the `tag` if needed for future needs, i.e. when in an end tag and needing
the attributes for a start tag.
Args:
param tag: The tag to get attributes from.
param attribute_name: The name of the attribute to get.
Expand Down
11 changes: 11 additions & 0 deletions tests/dj_angles/mappers/django/test_map_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ def test_string():
assert actual == expected


def test_is_end():
expected = "{% endblock %}"

html = "</dj-block>"
tag = create_tag(html)

actual = map_block(tag=tag)

assert actual == expected


def test_name_attribute():
expected = "{% block content %}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,41 @@ def test_typical():
assert actual == expected


def test_block():
expected = """
{% block content %}
{% endblock content %}"""

template = """
<dj-block name="content">
</dj-block name="content">"""
actual = replace_django_template_tags(template)

assert actual == expected


def test_block_different_name():
template = """
<dj-block name="content1">
</dj-block name="content2">"""

with pytest.raises(InvalidEndTagError):
replace_django_template_tags(template)


def test_block_missing_end_name():
expected = """
{% block content %}
{% endblock content %}"""

template = """
<dj-block name="content">
</dj-block>"""
actual = replace_django_template_tags(template)

assert actual == expected


def test_short_include():
expected = "<dj-partial>{% include 'partial.html' %}</dj-partial>"

Expand Down

0 comments on commit acd5254

Please sign in to comment.