|
2 | 2 | from __future__ import annotations |
3 | 3 |
|
4 | 4 | from typing import cast |
| 5 | +from typing import final |
5 | 6 |
|
6 | 7 | from django import template |
7 | 8 | from django.template.base import NodeList |
8 | 9 | from django.template.base import Parser |
9 | 10 | from django.template.base import Token |
10 | 11 | from django.template.context import Context |
11 | 12 | from django.utils.safestring import SafeString |
12 | | -from django.utils.safestring import mark_safe |
13 | 13 |
|
14 | | -from django_bird._typing import TagBits |
15 | 14 | from django_bird._typing import override |
16 | 15 |
|
17 | 16 | TAG = "bird:slot" |
|
21 | 20 |
|
22 | 21 |
|
23 | 22 | def do_slot(parser: Parser, token: Token) -> SlotNode: |
24 | | - bits = token.split_contents() |
25 | | - name = parse_slot_name(bits) |
26 | | - nodelist = parse_nodelist(parser) |
27 | | - return SlotNode(name, nodelist) |
28 | | - |
29 | | - |
30 | | -def parse_slot_name(bits: TagBits) -> str: |
31 | | - if len(bits) == 1: |
32 | | - return DEFAULT_SLOT |
33 | | - elif len(bits) == 2: |
34 | | - name = bits[1] |
35 | | - if name.startswith("name="): |
36 | | - name = name.split("=")[1] |
37 | | - else: |
38 | | - name = name |
39 | | - return name.strip("'\"") |
40 | | - else: |
41 | | - msg = f"{TAG} tag requires either no arguments, one argument, or 'name=\"slot_name\"'" |
| 23 | + _tag, *bits = token.split_contents() |
| 24 | + if len(bits) > 1: |
| 25 | + msg = f"{TAG} tag requires either one or no arguments" |
42 | 26 | raise template.TemplateSyntaxError(msg) |
43 | 27 |
|
| 28 | + if len(bits) == 0: |
| 29 | + name = DEFAULT_SLOT |
| 30 | + else: |
| 31 | + name = bits[0] |
| 32 | + if name.startswith("name="): |
| 33 | + _, name = name.split("=") |
| 34 | + name = name.strip("'\"") |
44 | 35 |
|
45 | | -def parse_nodelist(parser: Parser) -> NodeList: |
46 | 36 | nodelist = parser.parse((END_TAG,)) |
47 | 37 | parser.delete_first_token() |
48 | | - return nodelist |
| 38 | + |
| 39 | + return SlotNode(name, nodelist) |
49 | 40 |
|
50 | 41 |
|
| 42 | +@final |
51 | 43 | class SlotNode(template.Node): |
52 | 44 | def __init__(self, name: str, nodelist: NodeList): |
53 | 45 | self.name = name |
54 | 46 | self.nodelist = nodelist |
55 | 47 |
|
56 | 48 | @override |
57 | 49 | def render(self, context: Context) -> SafeString: |
58 | | - default_content: str = self.nodelist.render(context) |
59 | 50 | slots = context.get("slots") |
60 | 51 |
|
61 | 52 | if not slots or not isinstance(slots, dict): |
62 | | - return mark_safe(default_content) |
| 53 | + return self.nodelist.render(context) |
63 | 54 |
|
64 | 55 | slots_dict = cast(dict[str, str], slots) |
65 | 56 | slot_content = slots_dict.get(self.name) |
66 | 57 |
|
67 | 58 | if slot_content is None or slot_content == "": |
68 | | - return mark_safe(default_content) |
| 59 | + return self.nodelist.render(context) |
69 | 60 |
|
70 | | - t = template.Template(slot_content) |
71 | | - content = t.render(context) |
72 | | - return mark_safe(content) |
| 61 | + return template.Template(slot_content).render(context) |
0 commit comments