diff --git a/puppygirl/__main__.py b/puppygirl/__main__.py index 3fb2ec2..6ad8f88 100644 --- a/puppygirl/__main__.py +++ b/puppygirl/__main__.py @@ -2,7 +2,7 @@ from argparse import ArgumentParser from puppygirl import Puppygirl -from puppygirl.elements.domme import PuppygirlDomme +from puppygirl.elements.host import PuppygirlHost, PuppygirlPart from puppygirl.elements import Node from puppygirl.renderer import ClientSideRenderer, ServerSideRenderer @@ -24,7 +24,7 @@ def main(): case _: renderer = ServerSideRenderer() - pg = Puppygirl(renderer=renderer, elements=[PuppygirlDomme]) + pg = Puppygirl(renderer=renderer, elements=[PuppygirlHost, PuppygirlPart]) html = pg.parse(Node.from_path(args.input)) if args.pretty: diff --git a/puppygirl/assets/clientside.js b/puppygirl/assets/clientside.js index 90b7e0a..ff9962b 100644 --- a/puppygirl/assets/clientside.js +++ b/puppygirl/assets/clientside.js @@ -1,4 +1,4 @@ -class PuppygirlDomme extends HTMLElement { +class PuppygirlHost extends HTMLElement { constructor() { super() } @@ -14,4 +14,4 @@ class PuppygirlDomme extends HTMLElement { } -customElements.define("puppygirl-domme", PuppygirlDomme) +customElements.define("pg-host", PuppygirlDomme) diff --git a/puppygirl/elements/__init__.py b/puppygirl/elements/__init__.py index 632e28c..ac61cc3 100644 --- a/puppygirl/elements/__init__.py +++ b/puppygirl/elements/__init__.py @@ -1,3 +1,3 @@ from .constants import * -from .domme import * +from .host import * from .shadow_root import * diff --git a/puppygirl/elements/domme.py b/puppygirl/elements/domme.py deleted file mode 100644 index 3f4bf32..0000000 --- a/puppygirl/elements/domme.py +++ /dev/null @@ -1,31 +0,0 @@ -from dataclasses import dataclass -from typing import TYPE_CHECKING - -from .constants import TemplateAttr -from .shadow_root import ShadowRootMode -from ..renderer import Renderable - -if TYPE_CHECKING: - from .. import Puppygirl - from .shadow_root import Node - from ..puppytype import RenderableElement, Templates - -@dataclass -class PuppygirlDomme(Renderable): - puppygirl: "Puppygirl" - - @property - def name(self): - return "puppygirl-domme" - - def render(self, node: "Node", templates: "Templates") -> "RenderableElement": - if not node.has_attr(TemplateAttr): - return node - - template = templates[node[TemplateAttr]] - - shadow_root = node.attach_shadow(ShadowRootMode.Open) - shadow_root.append_child(template.clone()) - - return node - diff --git a/puppygirl/elements/host.py b/puppygirl/elements/host.py new file mode 100644 index 0000000..c0daa5a --- /dev/null +++ b/puppygirl/elements/host.py @@ -0,0 +1,67 @@ +from dataclasses import dataclass +from typing import TYPE_CHECKING + +from .constants import TemplateAttr +from .shadow_root import ShadowRootMode +from ..renderer import Query, Renderable + +if TYPE_CHECKING: + from .. import Puppygirl + from .shadow_root import Node + from ..puppytype import RenderableElement, Templates + +@dataclass +class PuppygirlHost(Renderable): + puppygirl: "Puppygirl" + + @property + def name(self): + return "pg-host" + + def query(self) -> Query: + return Query(self.name, attrs={ "template": True }) + + def render(self, node: "Node", templates: "Templates") -> "RenderableElement": + template = templates[node[TemplateAttr]] + + shadow_root = node.attach_shadow(ShadowRootMode.Open) + shadow_root.append_child(template.clone()) + + return node + +@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 render(self, node: "Node", templates: "Templates") -> "RenderableElement": + template = node.parent.find("template", recursive=False) + + if template is None: + return node + + part_name = node["for"] + parts = template.find_all(attrs={ "part": 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 + + return [] + + + + + diff --git a/puppygirl/elements/shadow_root.py b/puppygirl/elements/shadow_root.py index 623e659..c2260ee 100644 --- a/puppygirl/elements/shadow_root.py +++ b/puppygirl/elements/shadow_root.py @@ -80,6 +80,10 @@ class SingleNode(Node): def value(self): return self._value + @property + def parent(self): + return self._value.parent + def attach_shadow(self, shadow_root_mode: ShadowRootMode, clonable: Optional[bool] = None, delegates_focus: Optional[bool] = None, serializable: Optional[bool] = None): return ShadowRoot( host=self, diff --git a/puppygirl/renderer.py b/puppygirl/renderer.py index 15ebedc..69472a2 100644 --- a/puppygirl/renderer.py +++ b/puppygirl/renderer.py @@ -1,6 +1,8 @@ from dataclasses import InitVar, dataclass, field from importlib import resources -from typing import TYPE_CHECKING, Iterable, Protocol, runtime_checkable +from typing import TYPE_CHECKING, Any, Iterable, Protocol, Self, runtime_checkable + +from bs4 import Tag from puppygirl.elements import IdAttr, TemplateName from puppygirl.elements.shadow_root import Node, SingleNode @@ -10,10 +12,24 @@ if TYPE_CHECKING: from bs4 import BeautifulSoup from puppygirl import Puppygirl +class Query: + _args: Iterable[Any] + _kwargs: dict[str, Any] + + def __init__(self, *args, **kwargs): + self._args = args + self._kwargs = kwargs + + def query(self, tree: "BeautifulSoup") -> Iterable[Tag]: + return tree.find_all(*self._args, **self._kwargs) + @runtime_checkable class Renderable(Protocol): + def query(self) -> Query: + return Query() + def render(self, tree: "BeautifulSoup") -> "BeautifulSoup": - pass + return tree class Renderer(Protocol): def render(self, puppygirl: "Puppygirl", tree: "BeautifulSoup") -> "BeautifulSoup": @@ -35,6 +51,7 @@ class ClientSideRenderer(Renderer): head.append(script) return tree + class ServerSideRenderer(Renderer): def _find_local_templates(puppygirl: "Puppygirl", tree: "BeautifulSoup") -> "Templates": templates = tree.find_all(TemplateName) @@ -46,11 +63,13 @@ class ServerSideRenderer(Renderer): for element in puppygirl.elements: if hasattr(element, "name"): - tags = tree.find_all(element.name) + query = element.query() + tags = query.query(tree) tags.reverse() for tag in tags: new_tag = element.render( - SingleNode(tag).clone(), + SingleNode(tag), + # SingleNode(tag).clone(), templates )