mirror of
https://github.com/django-components/django-components.git
synced 2025-11-18 06:06:14 +00:00
feat: add BaseNode.contents (#1177)
This commit is contained in:
parent
661413d4a9
commit
5f4fbe76e5
6 changed files with 184 additions and 10 deletions
|
|
@ -2888,8 +2888,9 @@ class ComponentNode(BaseNode):
|
|||
flags: Optional[Dict[str, bool]] = None,
|
||||
nodelist: Optional[NodeList] = None,
|
||||
node_id: Optional[str] = None,
|
||||
contents: Optional[str] = None,
|
||||
) -> None:
|
||||
super().__init__(params=params, flags=flags, nodelist=nodelist, node_id=node_id)
|
||||
super().__init__(params=params, flags=flags, nodelist=nodelist, node_id=node_id, contents=contents)
|
||||
|
||||
self.name = name
|
||||
self.registry = registry
|
||||
|
|
|
|||
|
|
@ -313,11 +313,13 @@ class BaseNode(Node, metaclass=NodeMeta):
|
|||
flags: Optional[Dict[str, bool]] = None,
|
||||
nodelist: Optional[NodeList] = None,
|
||||
node_id: Optional[str] = None,
|
||||
contents: Optional[str] = None,
|
||||
):
|
||||
self.params = params
|
||||
self.flags = flags or {flag: False for flag in self.allowed_flags or []}
|
||||
self.nodelist = nodelist or NodeList()
|
||||
self.node_id = node_id or gen_id()
|
||||
self.contents = contents
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
|
|
@ -350,12 +352,13 @@ class BaseNode(Node, metaclass=NodeMeta):
|
|||
|
||||
trace_node_msg("PARSE", cls.tag, tag_id)
|
||||
|
||||
body = tag.parse_body()
|
||||
body, contents = tag.parse_body()
|
||||
node = cls(
|
||||
nodelist=body,
|
||||
node_id=tag_id,
|
||||
params=tag.params,
|
||||
flags=tag.flags,
|
||||
contents=contents,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ def resolve_params(
|
|||
class ParsedTag(NamedTuple):
|
||||
flags: Dict[str, bool]
|
||||
params: List[TagAttr]
|
||||
parse_body: Callable[[], NodeList]
|
||||
parse_body: Callable[[], Tuple[NodeList, Optional[str]]]
|
||||
|
||||
|
||||
def parse_template_tag(
|
||||
|
|
@ -140,13 +140,15 @@ def parse_template_tag(
|
|||
|
||||
raw_params, flags = _extract_flags(tag_name, attrs, allowed_flags or [])
|
||||
|
||||
def _parse_tag_body(parser: Parser, end_tag: str, inline: bool) -> NodeList:
|
||||
def _parse_tag_body(parser: Parser, end_tag: str, inline: bool) -> Tuple[NodeList, Optional[str]]:
|
||||
if inline:
|
||||
body = NodeList()
|
||||
contents: Optional[str] = None
|
||||
else:
|
||||
contents = _extract_contents_until(parser, [end_tag])
|
||||
body = parser.parse(parse_until=[end_tag])
|
||||
parser.delete_first_token()
|
||||
return body
|
||||
return body, contents
|
||||
|
||||
return ParsedTag(
|
||||
params=raw_params,
|
||||
|
|
@ -155,10 +157,53 @@ def parse_template_tag(
|
|||
# loggers before the parsing. This is because, if the body contains any other
|
||||
# tags, it will trigger their tag handlers. So the code called AFTER
|
||||
# `parse_body()` is already after all the nested tags were processed.
|
||||
parse_body=lambda: _parse_tag_body(parser, end_tag, is_inline) if end_tag else NodeList(),
|
||||
parse_body=lambda: _parse_tag_body(parser, end_tag, is_inline) if end_tag else (NodeList(), None),
|
||||
)
|
||||
|
||||
|
||||
# Similar to `parser.parse(parse_until=[end_tag])`, except:
|
||||
# 1. Does not remove the token it goes over (unlike `parser.parse()`, which mutates the parser state)
|
||||
# 2. Returns a string, instead of a NodeList
|
||||
#
|
||||
# This is used so we can access the contents of the tag body as strings, for example
|
||||
# to be used for caching slots.
|
||||
#
|
||||
# See https://github.com/django/django/blob/1fb3f57e81239a75eb8f873b392e11534c041fdc/django/template/base.py#L471
|
||||
def _extract_contents_until(parser: Parser, until_blocks: List[str]) -> str:
|
||||
contents: List[str] = []
|
||||
for token in reversed(parser.tokens):
|
||||
# Use the raw values here for TokenType.* for a tiny performance boost.
|
||||
token_type = token.token_type.value
|
||||
if token_type == 0: # TokenType.TEXT
|
||||
contents.append(token.contents)
|
||||
elif token_type == 1: # TokenType.VAR
|
||||
contents.append("{{ " + token.contents + " }}")
|
||||
elif token_type == 2: # TokenType.BLOCK
|
||||
try:
|
||||
command = token.contents.split()[0]
|
||||
except IndexError:
|
||||
# NOTE: Django's `Parser.parse()` raises a `TemplateSyntaxError` when there
|
||||
# was a an empty block tag, e.g. `{% %}`.
|
||||
# We skip raising an error here and let `Parser.parse()` raise it.
|
||||
contents.append("{% " + token.contents + " %}")
|
||||
if command in until_blocks:
|
||||
return "".join(contents)
|
||||
else:
|
||||
contents.append("{% " + token.contents + " %}")
|
||||
elif token_type == 3: # TokenType.COMMENT
|
||||
contents.append("{# " + token.contents + " #}")
|
||||
else:
|
||||
raise ValueError(f"Unknown token type {token_type}")
|
||||
|
||||
# NOTE: If we got here, then we've reached the end of the tag body without
|
||||
# encountering any of the `until_blocks`.
|
||||
# Django's `Parser.parse()` raises a `TemplateSyntaxError` in such case.
|
||||
#
|
||||
# Currently `_extract_contents_until()` runs right before `parser.parse()`,
|
||||
# so we skip raising an error here.
|
||||
return "".join(contents)
|
||||
|
||||
|
||||
def _extract_flags(
|
||||
tag_name: str, attrs: List[TagAttr], allowed_flags: List[str]
|
||||
) -> Tuple[List[TagAttr], Dict[str, bool]]:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue