+ This is a simple example of how to re-use template code in PyView.
+
+
+ This page includes a navbar that is defined in a separate file, and passes the user's avatar as a parameter:
+
+
+ {{ '{% include "includes/_navbar.html" with avatar_url=user.avatar_url %}' }}
+
+
+ Templates do have access to the parent template context, but it can be useful to have template parameters
+ (e.g. using a template in a for loop and passing each element as a parameter).
+
+
+ You read more about the include tag
+ feature in the template engine documentation.
+
+
\ No newline at end of file
diff --git a/examples/views/includes/includes.py b/examples/views/includes/includes.py
new file mode 100644
index 0000000..6b218bc
--- /dev/null
+++ b/examples/views/includes/includes.py
@@ -0,0 +1,34 @@
+from pyview import LiveView
+from dataclasses import dataclass, field
+import random
+
+
+@dataclass
+class User:
+ user_id: int = field(default_factory=lambda: random.randint(1, 100))
+
+ @property
+ def avatar_url(self):
+ return f"https://avatar.iran.liara.run/public/{self.user_id}"
+
+
+@dataclass
+class IncludesContext:
+ user: User = field(default_factory=User)
+ pages: list[str] = field(default_factory=lambda: ["home", "about", "contact"])
+ current_page: str = "home"
+
+
+class IncludesLiveView(LiveView):
+ """
+ Template Includes
+
+ This example shows how to include templates in other templates.
+ """
+
+ async def mount(self, socket, session):
+ socket.context = IncludesContext()
+
+ async def handle_params(self, url, params, socket):
+ if "page" in params:
+ socket.context.current_page = params["page"][0]
diff --git a/pyproject.toml b/pyproject.toml
index ab3cfb3..672d604 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ packages = [
{ include = "pyview" },
]
-version = "0.0.21"
+version = "0.0.22"
description = "LiveView in Python"
authors = ["Larry Ogrodnek "]
license = "MIT"
diff --git a/pyview/vendor/ibis/nodes.py b/pyview/vendor/ibis/nodes.py
index dcfd439..b3bd92a 100644
--- a/pyview/vendor/ibis/nodes.py
+++ b/pyview/vendor/ibis/nodes.py
@@ -203,6 +203,8 @@ def tree_parts(self, context) -> PartsTree:
resp.add_static(child.token.text if child.token else "")
elif isinstance(child, PrintNode):
resp.add_dynamic(child.wrender(context))
+ elif isinstance(child, IncludeNode):
+ resp.add_dynamic(child.tree_parts(context))
else:
resp.add_dynamic(child.tree_parts(context))
@@ -624,7 +626,7 @@ def process_token(self, token):
else:
raise errors.TemplateSyntaxError("Malformed 'include' tag.", token)
- def wrender(self, context):
+ def visit_node(self, context, visitor: NodeVisitor):
template_name = self.template_expr.eval(context)
if isinstance(template_name, str):
if ibis.loader:
@@ -632,9 +634,8 @@ def wrender(self, context):
context.push()
for name, expr in self.variables.items():
context[name] = expr.eval(context)
- rendered = template.root_node.render(context)
+ visitor(context, template.root_node)
context.pop()
- return rendered
else:
msg = f"No template loader has been specified. "
msg += f"A template loader is required by the 'include' tag in "
@@ -645,6 +646,18 @@ def wrender(self, context):
msg += f"The variable '{self.template_arg}' should evaluate to a string. "
msg += f"This variable has the value: {repr(template_name)}."
raise errors.TemplateRenderingError(msg, self.token)
+
+ def wrender(self, context):
+ output = []
+ self.visit_node(context, lambda ctx, node: output.append(node.render(ctx)))
+ return "".join(output)
+
+ def tree_parts(self, context) -> PartsTree:
+ output = []
+ def visitor(ctx, node):
+ output.append(node.tree_parts(ctx))
+ self.visit_node(context, visitor)
+ return output[0]
# ExtendsNodes implement template inheritance. They indicate that the current template inherits
diff --git a/tests/vendor/ibis/test_template_include.py b/tests/vendor/ibis/test_template_include.py
new file mode 100644
index 0000000..06f8b31
--- /dev/null
+++ b/tests/vendor/ibis/test_template_include.py
@@ -0,0 +1,22 @@
+from pyview.vendor.ibis import Template
+import pyview.vendor.ibis as ibis
+from pyview.vendor.ibis.loaders import DictLoader
+import pytest
+
+@pytest.fixture
+def template_loader():
+ ibis.loader = DictLoader(
+ {
+ "header.html": "