104 lines
2.4 KiB
Python
104 lines
2.4 KiB
Python
from dataclasses import dataclass
|
|
import re
|
|
from typing import TYPE_CHECKING
|
|
|
|
from .constants import TemplateAttr
|
|
from .shadow_root import ShadowRootMode, SingleNode
|
|
from ..renderer import Query, RenderState, Renderable
|
|
from .shadow_root import Node
|
|
|
|
if TYPE_CHECKING:
|
|
from .. import Puppygirl
|
|
from ..puppytype import RenderableElement
|
|
|
|
@dataclass
|
|
class PuppygirlHost(Renderable):
|
|
puppygirl: "Puppygirl"
|
|
|
|
@property
|
|
def name(self):
|
|
return "pg-host"
|
|
|
|
def query(self) -> Query:
|
|
return Query(self.name, attrs={ "template": True }, recursive=True)
|
|
|
|
def render(self, node: "Node", state: "RenderState") -> "RenderableElement":
|
|
node = node.clone()
|
|
|
|
template = state.templates.get(node.get_attr(TemplateAttr)).clone()
|
|
|
|
for tag in self.query().query(template):
|
|
result = self.render(SingleNode(tag), state)
|
|
Node.from_tag(tag).replace(result)
|
|
|
|
shadow_root = node.attach_shadow(ShadowRootMode.Open)
|
|
shadow_root.append_child(template.clone())
|
|
|
|
return node
|
|
|
|
def get_exported_name(part: str, mapping: str) -> str | None:
|
|
mapping = mapping.strip()
|
|
map_len = len(mapping)
|
|
|
|
if map_len == 0: return None
|
|
|
|
index = mapping.index(part)
|
|
end = index + len(part)
|
|
|
|
if end >= map_len or mapping[end] == ":":
|
|
return part
|
|
else:
|
|
try:
|
|
map_end = mapping.index(",", end)
|
|
return mapping[end + 1:map_end]
|
|
except:
|
|
return mapping[end + 1:]
|
|
|
|
@dataclass
|
|
class PuppygirlPart(Renderable):
|
|
puppygirl: "Puppygirl"
|
|
|
|
@property
|
|
def name(self):
|
|
return "pg-part"
|
|
|
|
def query(self) -> Query:
|
|
return Query(self.name, attrs={ "for": True })
|
|
|
|
def replace_part(self, node: "Node", part_name: str):
|
|
template = node.parent.find("template", recursive=False)
|
|
|
|
if template is None:
|
|
return node
|
|
|
|
parts = template(part=part_name, recusive=False)
|
|
exports = template(exportparts=re.compile(part_name), recursive=False)
|
|
|
|
for export in exports:
|
|
mapping = get_exported_name(part_name, export["exportparts"])
|
|
if mapping is None: continue
|
|
|
|
self.replace_part(SingleNode(export), part_name)
|
|
|
|
attrs = {
|
|
attr: value
|
|
for attr, value in node.value.attrs.items()
|
|
if attr != "for"
|
|
}
|
|
|
|
for attr, value in attrs.items():
|
|
for part in parts:
|
|
part[attr] = value
|
|
|
|
|
|
def render(self, node: "Node", state: "RenderState") -> "RenderableElement":
|
|
part_name = node["for"]
|
|
|
|
self.replace_part(node, part_name)
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|