mirror of
https://github.com/django-components/django-components.git
synced 2025-09-11 16:36:17 +00:00
Rework of context handling (#18)
Co-authored-by: rbeard0330 <@dul2k3BKW6m>
This commit is contained in:
parent
88fe2fc3b7
commit
93b8a7404a
9 changed files with 305 additions and 59 deletions
|
@ -1,5 +1,4 @@
|
||||||
from django.forms.widgets import MediaDefiningClass
|
from django.forms.widgets import MediaDefiningClass
|
||||||
from django.template import Context
|
|
||||||
from django.template.base import NodeList, TextNode
|
from django.template.base import NodeList, TextNode
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
@ -8,12 +7,6 @@ from six import with_metaclass
|
||||||
# Allow "component.AlreadyRegistered" instead of having to import these everywhere
|
# Allow "component.AlreadyRegistered" instead of having to import these everywhere
|
||||||
from django_components.component_registry import AlreadyRegistered, ComponentRegistry, NotRegistered # noqa
|
from django_components.component_registry import AlreadyRegistered, ComponentRegistry, NotRegistered # noqa
|
||||||
|
|
||||||
# Python 2 compatibility
|
|
||||||
try:
|
|
||||||
from inspect import getfullargspec
|
|
||||||
except ImportError:
|
|
||||||
from inspect import getargspec as getfullargspec
|
|
||||||
|
|
||||||
# Django < 2.1 compatibility
|
# Django < 2.1 compatibility
|
||||||
try:
|
try:
|
||||||
from django.template.base import TokenType
|
from django.template.base import TokenType
|
||||||
|
@ -49,52 +42,40 @@ class Component(with_metaclass(MediaDefiningClass)):
|
||||||
return mark_safe("\n".join(self.media.render_js()))
|
return mark_safe("\n".join(self.media.render_js()))
|
||||||
|
|
||||||
def slots_in_template(self, template):
|
def slots_in_template(self, template):
|
||||||
nodelist = NodeList()
|
return NodeList(node for node in template.template.nodelist if is_slot_node(node))
|
||||||
for node in template.template.nodelist:
|
|
||||||
if (
|
|
||||||
node.token.token_type == TokenType.BLOCK
|
|
||||||
and node.token.split_contents()[0] == "slot"
|
|
||||||
):
|
|
||||||
nodelist.append(node)
|
|
||||||
|
|
||||||
return nodelist
|
def render(self, context, slots_filled=None):
|
||||||
|
|
||||||
def render(self, slots_filled=None, *args, **kwargs):
|
|
||||||
slots_filled = slots_filled or []
|
slots_filled = slots_filled or []
|
||||||
context_args_variables = getfullargspec(self.context).args[1:]
|
|
||||||
context_args = {
|
|
||||||
key: kwargs[key] for key in context_args_variables if key in kwargs
|
|
||||||
}
|
|
||||||
context = self.context(**context_args)
|
|
||||||
template = get_template(self.template(context))
|
template = get_template(self.template(context))
|
||||||
slots_in_template = self.slots_in_template(template)
|
slots_in_template = self.slots_in_template(template)
|
||||||
|
|
||||||
if slots_in_template:
|
# If there are no slots, then we can simply render the template
|
||||||
valid_slot_names = set([slot.name for slot in slots_in_template])
|
if not slots_in_template:
|
||||||
nodelist = NodeList()
|
return template.template.render(context)
|
||||||
for node in template.template.nodelist:
|
|
||||||
if (
|
# Otherwise, we need to assemble and render a nodelist containing the nodes from the template, slots that were
|
||||||
node.token.token_type == TokenType.BLOCK
|
# provided when the component was called (previously rendered by the component's render method) and the
|
||||||
and node.token.split_contents()[0] == "slot"
|
# unrendered default slots
|
||||||
):
|
nodelist = NodeList()
|
||||||
if node.name in valid_slot_names and node.name in slots_filled:
|
for node in template.template.nodelist:
|
||||||
nodelist.append(TextNode(slots_filled[node.name]))
|
if is_slot_node(node):
|
||||||
else:
|
if node.name in slots_filled:
|
||||||
for node in node.nodelist:
|
nodelist.append(TextNode(slots_filled[node.name]))
|
||||||
nodelist.append(node)
|
|
||||||
else:
|
else:
|
||||||
nodelist.append(node)
|
nodelist.extend(node.nodelist)
|
||||||
|
else:
|
||||||
|
nodelist.append(node)
|
||||||
|
|
||||||
render_context = Context(context)
|
return nodelist.render(context)
|
||||||
with render_context.bind_template(template.template):
|
|
||||||
return nodelist.render(render_context)
|
|
||||||
|
|
||||||
return template.render(context)
|
|
||||||
|
|
||||||
class Media:
|
class Media:
|
||||||
css = {}
|
css = {}
|
||||||
js = []
|
js = []
|
||||||
|
|
||||||
|
|
||||||
|
def is_slot_node(node):
|
||||||
|
return node.token.token_type == TokenType.BLOCK and node.token.split_contents()[0] == "slot"
|
||||||
|
|
||||||
|
|
||||||
# This variable represents the global component registry
|
# This variable represents the global component registry
|
||||||
registry = ComponentRegistry()
|
registry = ComponentRegistry()
|
||||||
|
|
|
@ -88,7 +88,8 @@ def component_js_dependencies_tag():
|
||||||
def component_tag(name, *args, **kwargs):
|
def component_tag(name, *args, **kwargs):
|
||||||
component_class = registry.get(name)
|
component_class = registry.get(name)
|
||||||
component = component_class()
|
component = component_class()
|
||||||
return component.render(*args, **kwargs)
|
context = template.Context(component.context(*args, **kwargs))
|
||||||
|
return component.render(context)
|
||||||
|
|
||||||
|
|
||||||
class SlotNode(Node):
|
class SlotNode(Node):
|
||||||
|
@ -129,27 +130,30 @@ def do_slot(parser, token, component=None):
|
||||||
|
|
||||||
|
|
||||||
class ComponentNode(Node):
|
class ComponentNode(Node):
|
||||||
def __init__(self, component, extra_context, slots):
|
def __init__(self, component, context_kwargs, slots):
|
||||||
extra_context = extra_context or {}
|
self.context_kwargs = context_kwargs or {}
|
||||||
self.component, self.extra_context, self.slots = component, extra_context, slots
|
self.component, self.slots = component, slots
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Component Node: %s. Contents: %r>" % (self.component, self.slots)
|
return "<Component Node: %s. Contents: %r>" % (self.component, self.slots)
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
extra_context = {
|
# Resolve FilterExpressions and Variables that were passed as args to the component, then call component's
|
||||||
|
# context method to get values to insert into the context
|
||||||
|
resolved_context_kwargs = {
|
||||||
key: context_item.resolve(context) if hasattr(context_item, 'resolve') else context_item
|
key: context_item.resolve(context) if hasattr(context_item, 'resolve') else context_item
|
||||||
for key, context_item in self.extra_context.items()
|
for key, context_item in self.context_kwargs.items()
|
||||||
}
|
}
|
||||||
context.update(extra_context)
|
extra_context = self.component.context(**resolved_context_kwargs)
|
||||||
|
|
||||||
self.slots.render(context)
|
with context.update(extra_context):
|
||||||
|
self.slots.render(context)
|
||||||
|
if COMPONENT_CONTEXT_KEY in context.render_context:
|
||||||
|
slots_filled = context.render_context[COMPONENT_CONTEXT_KEY][self.component]
|
||||||
|
else:
|
||||||
|
slots_filled = []
|
||||||
|
|
||||||
if COMPONENT_CONTEXT_KEY in context.render_context:
|
return self.component.render(context, slots_filled=slots_filled)
|
||||||
slots_filled = context.render_context[COMPONENT_CONTEXT_KEY][self.component]
|
|
||||||
return self.component.render(slots_filled=slots_filled, **context.flatten())
|
|
||||||
|
|
||||||
return self.component.render(**extra_context)
|
|
||||||
|
|
||||||
|
|
||||||
@register.tag("component_block")
|
@register.tag("component_block")
|
||||||
|
@ -187,9 +191,9 @@ def do_component(parser, token):
|
||||||
component_class = registry.get(component_name)
|
component_class = registry.get(component_name)
|
||||||
component = component_class()
|
component = component_class()
|
||||||
|
|
||||||
extra_context = {}
|
context_kwargs = {}
|
||||||
if len(bits) > 2:
|
if len(bits) > 2:
|
||||||
extra_context = component.context(**token_kwargs(bits[2:], parser))
|
context_kwargs = token_kwargs(bits[2:], parser)
|
||||||
|
|
||||||
slots_filled = NodeList()
|
slots_filled = NodeList()
|
||||||
tag_name = bits[0]
|
tag_name = bits[0]
|
||||||
|
@ -205,4 +209,4 @@ def do_component(parser, token):
|
||||||
elif tag_name == "endcomponent_block":
|
elif tag_name == "endcomponent_block":
|
||||||
break
|
break
|
||||||
|
|
||||||
return ComponentNode(component, extra_context, slots_filled)
|
return ComponentNode(component, context_kwargs, slots_filled)
|
||||||
|
|
0
tests/templates/child_template.html
Normal file
0
tests/templates/child_template.html
Normal file
2
tests/templates/incrementer.html
Normal file
2
tests/templates/incrementer.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
{% load component_tags %}<p class="incrementer">value={{ value }};calls={{ calls }}</p>
|
||||||
|
{% slot 'content' %}{% endslot %}
|
12
tests/templates/parent_template.html
Normal file
12
tests/templates/parent_template.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% load component_tags %}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Parent content</h1>
|
||||||
|
{% component name="variable_display" shadowing_variable='override' new_variable='unique_val' %}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{% slot 'content' %}
|
||||||
|
<h2>Slot content</h2>
|
||||||
|
{% component name="variable_display" shadowing_variable='slot_default_override' new_variable='slot_default_unique' %}
|
||||||
|
{% endslot %}
|
||||||
|
</div>
|
12
tests/templates/parent_with_args_template.html
Normal file
12
tests/templates/parent_with_args_template.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% load component_tags %}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Parent content</h1>
|
||||||
|
{% component name="variable_display" shadowing_variable=inner_parent_value new_variable='unique_val' %}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{% slot 'content' %}
|
||||||
|
<h2>Slot content</h2>
|
||||||
|
{% component name="variable_display" shadowing_variable='slot_default_override' new_variable=inner_parent_value %}
|
||||||
|
{% endslot %}
|
||||||
|
</div>
|
4
tests/templates/variable_display.html
Normal file
4
tests/templates/variable_display.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% load component_tags %}
|
||||||
|
|
||||||
|
<h1>Shadowing variable = {{ shadowing_variable }}</h1>
|
||||||
|
<h1>Uniquely named variable = {{ unique_variable }}</h1>
|
|
@ -1,5 +1,7 @@
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
|
from django.template import Context
|
||||||
|
|
||||||
from django_components import component
|
from django_components import component
|
||||||
|
|
||||||
from .django_test_setup import * # NOQA
|
from .django_test_setup import * # NOQA
|
||||||
|
@ -29,13 +31,14 @@ class ComponentRegistryTest(SimpleTestCase):
|
||||||
js = ["script.js"]
|
js = ["script.js"]
|
||||||
|
|
||||||
comp = SimpleComponent()
|
comp = SimpleComponent()
|
||||||
|
context = Context(comp.context(variable="test"))
|
||||||
|
|
||||||
self.assertHTMLEqual(comp.render_dependencies(), dedent("""
|
self.assertHTMLEqual(comp.render_dependencies(), dedent("""
|
||||||
<link href="style.css" type="text/css" media="all" rel="stylesheet">
|
<link href="style.css" type="text/css" media="all" rel="stylesheet">
|
||||||
<script src="script.js"></script>
|
<script src="script.js"></script>
|
||||||
""").strip())
|
""").strip())
|
||||||
|
|
||||||
self.assertHTMLEqual(comp.render(variable="test"), dedent("""
|
self.assertHTMLEqual(comp.render(context), dedent("""
|
||||||
Variable: <strong>test</strong>
|
Variable: <strong>test</strong>
|
||||||
""").lstrip())
|
""").lstrip())
|
||||||
|
|
||||||
|
@ -66,8 +69,9 @@ class ComponentRegistryTest(SimpleTestCase):
|
||||||
return "filtered_template.html"
|
return "filtered_template.html"
|
||||||
|
|
||||||
comp = FilteredComponent()
|
comp = FilteredComponent()
|
||||||
|
context = Context(comp.context(var1="test1", var2="test2"))
|
||||||
|
|
||||||
self.assertHTMLEqual(comp.render(var1="test1", var2="test2"), dedent("""
|
self.assertHTMLEqual(comp.render(context), dedent("""
|
||||||
Var1: <strong>test1</strong>
|
Var1: <strong>test1</strong>
|
||||||
Var2 (uppercased): <strong>TEST2</strong>
|
Var2 (uppercased): <strong>TEST2</strong>
|
||||||
""").lstrip())
|
""").lstrip())
|
||||||
|
|
227
tests/test_context.py
Normal file
227
tests/test_context.py
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
from django.template import Context, Template
|
||||||
|
|
||||||
|
from django_components import component
|
||||||
|
|
||||||
|
from .django_test_setup import * # NOQA
|
||||||
|
from .testutils import Django111CompatibleSimpleTestCase as SimpleTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class ParentComponent(component.Component):
|
||||||
|
def context(self):
|
||||||
|
return {
|
||||||
|
"shadowing_variable": 'NOT SHADOWED'
|
||||||
|
}
|
||||||
|
|
||||||
|
def template(self, context):
|
||||||
|
return "parent_template.html"
|
||||||
|
|
||||||
|
|
||||||
|
class ParentComponentWithArgs(component.Component):
|
||||||
|
def context(self, parent_value):
|
||||||
|
return {
|
||||||
|
"inner_parent_value": parent_value
|
||||||
|
}
|
||||||
|
|
||||||
|
def template(self, context):
|
||||||
|
return "parent_with_args_template.html"
|
||||||
|
|
||||||
|
|
||||||
|
class VariableDisplay(component.Component):
|
||||||
|
def context(self, shadowing_variable, new_variable):
|
||||||
|
return {
|
||||||
|
"shadowing_variable": shadowing_variable,
|
||||||
|
"unique_variable": new_variable
|
||||||
|
}
|
||||||
|
|
||||||
|
def template(self, context):
|
||||||
|
return "variable_display.html"
|
||||||
|
|
||||||
|
|
||||||
|
class IncrementerComponent(component.Component):
|
||||||
|
def context(self, value=0):
|
||||||
|
value = int(value)
|
||||||
|
if hasattr(self, 'call_count'):
|
||||||
|
self.call_count += 1
|
||||||
|
else:
|
||||||
|
self.call_count = 1
|
||||||
|
return {
|
||||||
|
"value": value + 1,
|
||||||
|
"calls": self.call_count
|
||||||
|
}
|
||||||
|
|
||||||
|
def template(self, context):
|
||||||
|
return "incrementer.html"
|
||||||
|
|
||||||
|
|
||||||
|
component.registry.register(name='parent_component', component=ParentComponent)
|
||||||
|
component.registry.register(name='parent_with_args', component=ParentComponentWithArgs)
|
||||||
|
component.registry.register(name='variable_display', component=VariableDisplay)
|
||||||
|
component.registry.register(name='incrementer', component=IncrementerComponent)
|
||||||
|
|
||||||
|
|
||||||
|
class ContextTests(SimpleTestCase):
|
||||||
|
def test_nested_component_context_shadows_parent_with_unfilled_slots_and_component_tag(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component 'parent_component' %}")
|
||||||
|
rendered = template.render(Context())
|
||||||
|
|
||||||
|
self.assertIn('<h1>Shadowing variable = override</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Shadowing variable = slot_default_override</h1>', rendered, rendered)
|
||||||
|
self.assertNotIn('<h1>Shadowing variable = NOT SHADOWED</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_nested_component_instances_have_unique_context_with_unfilled_slots_and_component_tag(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component name='parent_component' %}")
|
||||||
|
rendered = template.render(Context())
|
||||||
|
|
||||||
|
self.assertIn('<h1>Uniquely named variable = unique_val</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Uniquely named variable = slot_default_unique</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_nested_component_context_shadows_parent_with_unfilled_slots_and_component_block_tag(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'parent_component' %}{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context())
|
||||||
|
|
||||||
|
self.assertIn('<h1>Shadowing variable = override</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Shadowing variable = slot_default_override</h1>', rendered, rendered)
|
||||||
|
self.assertNotIn('<h1>Shadowing variable = NOT SHADOWED</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_nested_component_instances_have_unique_context_with_unfilled_slots_and_component_block_tag(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'parent_component' %}{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context())
|
||||||
|
|
||||||
|
self.assertIn('<h1>Uniquely named variable = unique_val</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Uniquely named variable = slot_default_unique</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_nested_component_context_shadows_parent_with_filled_slots(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'parent_component' %}"
|
||||||
|
"{% slot 'content' %}{% component name='variable_display' "
|
||||||
|
"shadowing_variable='shadow_from_slot' new_variable='unique_from_slot' %}{% endslot %}"
|
||||||
|
"{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context())
|
||||||
|
|
||||||
|
self.assertIn('<h1>Shadowing variable = override</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Shadowing variable = shadow_from_slot</h1>', rendered, rendered)
|
||||||
|
self.assertNotIn('<h1>Shadowing variable = NOT SHADOWED</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_nested_component_instances_have_unique_context_with_filled_slots(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'parent_component' %}"
|
||||||
|
"{% slot 'content' %}{% component name='variable_display' "
|
||||||
|
"shadowing_variable='shadow_from_slot' new_variable='unique_from_slot' %}{% endslot %}"
|
||||||
|
"{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context())
|
||||||
|
|
||||||
|
self.assertIn('<h1>Uniquely named variable = unique_val</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Uniquely named variable = unique_from_slot</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_nested_component_context_shadows_outer_context_with_unfilled_slots_and_component_tag(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component name='parent_component' %}")
|
||||||
|
rendered = template.render(Context({'shadowing_variable': 'NOT SHADOWED'}))
|
||||||
|
|
||||||
|
self.assertIn('<h1>Shadowing variable = override</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Shadowing variable = slot_default_override</h1>', rendered, rendered)
|
||||||
|
self.assertNotIn('<h1>Shadowing variable = NOT SHADOWED</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_nested_component_context_shadows_outer_context_with_unfilled_slots_and_component_block_tag(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'parent_component' %}{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context({'shadowing_variable': 'NOT SHADOWED'}))
|
||||||
|
|
||||||
|
self.assertIn('<h1>Shadowing variable = override</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Shadowing variable = slot_default_override</h1>', rendered, rendered)
|
||||||
|
self.assertNotIn('<h1>Shadowing variable = NOT SHADOWED</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_nested_component_context_shadows_outer_context_with_filled_slots(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'parent_component' %}"
|
||||||
|
"{% slot 'content' %}{% component name='variable_display' "
|
||||||
|
"shadowing_variable='shadow_from_slot' new_variable='unique_from_slot' %}{% endslot %}"
|
||||||
|
"{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context({'shadowing_variable': 'NOT SHADOWED'}))
|
||||||
|
|
||||||
|
self.assertIn('<h1>Shadowing variable = override</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Shadowing variable = shadow_from_slot</h1>', rendered, rendered)
|
||||||
|
self.assertNotIn('<h1>Shadowing variable = NOT SHADOWED</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
|
||||||
|
class ParentArgsTests(SimpleTestCase):
|
||||||
|
def test_parent_args_can_be_drawn_from_context(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'parent_with_args' parent_value=parent_value %}"
|
||||||
|
"{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context({'parent_value': 'passed_in'}))
|
||||||
|
|
||||||
|
self.assertIn('<h1>Shadowing variable = passed_in</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Uniquely named variable = passed_in</h1>', rendered, rendered)
|
||||||
|
self.assertNotIn('<h1>Shadowing variable = NOT SHADOWED</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_parent_args_available_outside_slots(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'parent_with_args' parent_value='passed_in' %}{%endcomponent_block %}")
|
||||||
|
rendered = template.render(Context())
|
||||||
|
|
||||||
|
self.assertIn('<h1>Shadowing variable = passed_in</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Uniquely named variable = passed_in</h1>', rendered, rendered)
|
||||||
|
self.assertNotIn('<h1>Shadowing variable = NOT SHADOWED</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
def test_parent_args_available_in_slots(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'parent_with_args' parent_value='passed_in' %}"
|
||||||
|
"{% slot 'content' %}{% component name='variable_display' "
|
||||||
|
"shadowing_variable='value_from_slot' new_variable=inner_parent_value %}{% endslot %}"
|
||||||
|
"{%endcomponent_block %}")
|
||||||
|
rendered = template.render(Context())
|
||||||
|
|
||||||
|
self.assertIn('<h1>Shadowing variable = value_from_slot</h1>', rendered, rendered)
|
||||||
|
self.assertIn('<h1>Uniquely named variable = passed_in</h1>', rendered, rendered)
|
||||||
|
self.assertNotIn('<h1>Shadowing variable = NOT SHADOWED</h1>', rendered, rendered)
|
||||||
|
|
||||||
|
|
||||||
|
class ContextCalledOnceTests(SimpleTestCase):
|
||||||
|
def test_one_context_call_with_simple_component(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component name='incrementer' %}")
|
||||||
|
rendered = template.render(Context()).strip()
|
||||||
|
|
||||||
|
self.assertEqual(rendered, '<p class="incrementer">value=1;calls=1</p>', rendered)
|
||||||
|
|
||||||
|
def test_one_context_call_with_simple_component_and_arg(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component name='incrementer' value='2' %}")
|
||||||
|
rendered = template.render(Context()).strip()
|
||||||
|
|
||||||
|
self.assertEqual(rendered, '<p class="incrementer">value=3;calls=1</p>', rendered)
|
||||||
|
|
||||||
|
def test_one_context_call_with_component_block(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'incrementer' %}{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context()).strip()
|
||||||
|
|
||||||
|
self.assertEqual(rendered, '<p class="incrementer">value=1;calls=1</p>', rendered)
|
||||||
|
|
||||||
|
def test_one_context_call_with_component_block_and_arg(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'incrementer' value='3' %}{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context()).strip()
|
||||||
|
|
||||||
|
self.assertEqual(rendered, '<p class="incrementer">value=4;calls=1</p>', rendered)
|
||||||
|
|
||||||
|
def test_one_context_call_with_slot(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'incrementer' %}{% slot 'content' %}"
|
||||||
|
"<p>slot</p>{% endslot %}{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context()).strip()
|
||||||
|
|
||||||
|
self.assertEqual(rendered, '<p class="incrementer">value=1;calls=1</p>\n<p>slot</p>', rendered)
|
||||||
|
|
||||||
|
def test_one_context_call_with_slot_and_arg(self):
|
||||||
|
template = Template("{% load component_tags %}{% component_dependencies %}"
|
||||||
|
"{% component_block 'incrementer' value='3' %}{% slot 'content' %}"
|
||||||
|
"<p>slot</p>{% endslot %}{% endcomponent_block %}")
|
||||||
|
rendered = template.render(Context()).strip()
|
||||||
|
|
||||||
|
self.assertEqual(rendered, '<p class="incrementer">value=4;calls=1</p>\n<p>slot</p>', rendered)
|
Loading…
Add table
Add a link
Reference in a new issue