Made c-vars optional

This commit is contained in:
Will Abbott 2024-07-06 00:49:15 +01:00
parent 8aa156cf8c
commit 0c55ca9f18
6 changed files with 37 additions and 50 deletions

View file

@ -135,8 +135,8 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# COTTON_TEMPLATE_CACHING_ENABLED = False
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.dummy.DummyCache",
}
}
# CACHES = {
# "default": {
# "BACKEND": "django.core.cache.backends.dummy.DummyCache",
# }
# }

View file

@ -46,7 +46,7 @@ settings.configure(
django.setup()
def benchmark_template_rendering(template_name, iterations=1):
def benchmark_template_rendering(template_name, iterations=10000):
start_time = time.time()
for _ in range(iterations):
render_to_string(template_name)

View file

@ -103,7 +103,6 @@ class CottonTemplateProcessor:
content = self._replace_syntax_with_placeholders(content)
content = self._compile_cotton_to_django(content, component_key)
content = self._replace_placeholders_with_syntax(content)
print(content)
return self._revert_bs4_attribute_empty_attribute_fixing(content)
def _replace_syntax_with_placeholders(self, content):
@ -139,14 +138,10 @@ class CottonTemplateProcessor:
"""Convert cotton <c-* syntax to {%."""
soup = BeautifulSoup(html_content, "html.parser")
# TODO: Performance optimisation - Make vars_frame optional, only adding it when the user actually provided
# vars in a component
# check if soup contains a 'c-vars' tag
# if soup.find("c-vars"):
# soup = self._wrap_with_cotton_vars_frame(soup)
if cvars_el := soup.find("c-vars"):
soup = self._wrap_with_cotton_vars_frame(soup, cvars_el)
soup = self._wrap_with_cotton_vars_frame(soup)
self._transform_components(soup, component_key)
return str(soup.encode(formatter=UnsortedAttributes()).decode("utf-8"))
@ -179,29 +174,25 @@ class CottonTemplateProcessor:
return contents
def _wrap_with_cotton_vars_frame(self, soup):
def _wrap_with_cotton_vars_frame(self, soup, cvars_el):
"""Wrap content with {% cotton_vars_frame %} to be able to govern vars and attributes. In order to recognise
vars defined in a component and also have them available in the same component's context, we wrap the entire
contents in another component: cotton_vars_frame."""
vars_with_defaults = []
c_vars = soup.find("c-vars")
for var, value in cvars_el.attrs.items():
if value is None:
vars_with_defaults.append(f"{var}={var}")
elif var.startswith(":"):
# If ':' is present, the user wants to parse a literal string as the default value,
# i.e. "['a', 'b']", "{'a': 'b'}", "True", "False", "None" or "1".
var = var[1:] # Remove the ':' prefix
vars_with_defaults.append(f'{var}={var}|eval_default:"{value}"')
else:
# Assuming value is already a string that represents the default value
vars_with_defaults.append(f'{var}={var}|default:"{value}"')
# parse c-vars tag to extract variables and defaults
if c_vars:
vars_with_defaults = []
for var, value in c_vars.attrs.items():
if value is None:
vars_with_defaults.append(f"{var}={var}")
elif var.startswith(":"):
# If ':' is present, the user wants to parse a literal string as the default value,
# i.e. "['a', 'b']", "{'a': 'b'}", "True", "False", "None" or "1".
var = var[1:] # Remove the ':' prefix
vars_with_defaults.append(f'{var}={var}|eval_default:"{value}"')
else:
# Assuming value is already a string that represents the default value
vars_with_defaults.append(f'{var}={var}|default:"{value}"')
c_vars.decompose()
cvars_el.decompose()
# Construct the {% with %} opening tag
opening = "{% cotton_vars_frame " + " ".join(vars_with_defaults) + " %}"

View file

@ -3,6 +3,9 @@ import ast
from django import template
from django.template import Node
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from django_cotton.utils import ensure_quoted
def cotton_component(parser, token):
@ -42,7 +45,7 @@ class CottonComponentNode(Node):
value = value.strip("'\"")
if key.startswith(":"):
key = key[1:] # Remove ':' prefix
key = key[1:]
attrs[key] = self.process_dynamic_attribute(value, context)
elif value == "":
attrs[key] = True
@ -63,20 +66,20 @@ class CottonComponentNode(Node):
for expression_attr in component_slots["ctn_template_expression_attrs"]:
attrs[expression_attr] = component_slots[expression_attr]
# Make the attrs available in the context for the vars frame
local_context["attrs_dict"] = attrs
# Reset the component's slots in context to prevent bleeding into sibling components
if self.component_key in all_slots:
all_slots[self.component_key] = {}
# if self.component_key in all_slots:
all_slots[self.component_key] = {}
# Provide all of the attrs as a string to pass to the component
# local_context.update(attrs)
# attrs = " ".join(
# [f"{key}={ensure_quoted(value)}" for key, value in attrs.items()]
# )
# local_context.update({"attrs": mark_safe(attrs)})
local_context.update(attrs)
attrs_string = " ".join(
f"{key}={ensure_quoted(value)}" for key, value in attrs.items()
)
local_context["attrs"] = mark_safe(attrs_string)
context.update({"cotton_slots": all_slots})
return render_to_string(self.template_path, local_context)
def process_dynamic_attribute(self, value, context):

View file

@ -2,6 +2,8 @@ from django import template
from django.template.base import token_kwargs
from django.utils.safestring import mark_safe
from django_cotton.utils import ensure_quoted
register = template.Library()
@ -46,12 +48,6 @@ class CottonVarsFrameNode(template.Node):
context["attrs_dict"] = attrs_without_vars
# Provide all of the attrs as a string to pass to the component
def ensure_quoted(value):
if isinstance(value, str) and value.startswith('"') and value.endswith('"'):
return value
else:
return f'"{value}"'
attrs = " ".join(
[
f"{key}={ensure_quoted(value)}"
@ -59,8 +55,7 @@ class CottonVarsFrameNode(template.Node):
]
)
context.update({"attrs": mark_safe(attrs)})
context.update(attrs_without_vars)
context["attrs"] = mark_safe(attrs)
context.update(vars)
return self.nodelist.render(context)

View file

@ -63,8 +63,6 @@ class InlineTestCase(CottonInlineTestCase):
with self.settings(ROOT_URLCONF=self.get_url_conf()):
response = self.client.get("/view/")
print(response.content.decode())
self.assertTrue(
"""{
attr1: 'im an attr',