Coverage for phml\nodes\element.py: 60%
48 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-30 09:38 -0600
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-30 09:38 -0600
1from __future__ import annotations
3from typing import TYPE_CHECKING, Optional
5from .parent import Parent
7if TYPE_CHECKING:
8 from .position import Position
9 from .root import Root
10 from .types import Properties
13class Element(Parent):
14 """Element (Parent) represents an Element ([DOM]).
16 A tagName field must be present. It represents the element's local name ([DOM]).
18 The properties field represents information associated with the element.
19 The value of the properties field implements the Properties interface.
21 If the tagName field is 'template', a content field can be present. The value
22 of the content field implements the Root interface.
24 If the tagName field is 'template', the element must be a leaf.
26 If the tagName field is 'noscript', its children should be represented as if
27 scripting is disabled ([HTML]).
30 For example, the following HTML:
32 ```html
33 <a href="https://alpha.com" class="bravo" download></a>
34 ```
36 Yields:
38 ```javascript
39 {
40 type: 'element',
41 tagName: 'a',
42 properties: {
43 href: 'https://alpha.com',
44 className: ['bravo'],
45 download: true
46 },
47 children: []
48 }
49 ```
50 """
52 def __init__(
53 self,
54 tag: str = "element",
55 properties: Optional[Properties] = {},
56 parent: Optional[Element | Root] = None,
57 startend: bool = False,
58 position: Optional[Position] = None,
59 children: Optional[list] = None,
60 ):
61 super().__init__(position, children)
62 self.properties = properties
63 self.tag = tag
64 self.startend = startend
65 self.parent = parent
66 self.locals = {}
68 def __eq__(self, obj) -> bool:
69 if obj is None:
70 return False
72 if obj.type == self.type:
73 if self.tag != obj.tag:
74 return False
75 if self.startend != obj.startend:
76 return False
77 if self.properties != obj.properties:
78 return False
80 for c, oc in zip(self.children, obj.children):
81 if c != oc:
82 return False
83 return True
84 else:
85 return False
87 def start_tag(self) -> str:
88 """Builds the open/start tag for the element.
90 Note:
91 It will return `/>` if the tag is self closing.
93 Returns:
94 str: Built element start tag.
95 """
96 opening = f"<{self.tag}"
98 attributes = []
99 for prop in self.properties:
100 if isinstance(self.properties[prop], bool) or self.properties[prop] in ["yes", "no"]:
101 if self.properties[prop] == "yes" or self.properties[prop]:
102 attributes.append(prop)
103 else:
104 attributes.append(f'{prop}="{self.properties[prop]}"')
105 if len(attributes) > 0:
106 attributes = " " + " ".join(attributes)
107 else:
108 attributes = ""
110 closing = f"{' /' if self.startend else ''}>"
112 return opening + attributes + closing
114 def end_tag(self) -> str:
115 """Build the elements end tag.
117 Returns:
118 str: Built element end tag.
119 """
120 return f"</{self.tag}>" if not self.startend else None
122 def __repr__(self) -> str:
123 out = f"{self.type}(tag: {self.tag}, properties: {self.properties}, children: {len(self.children)})"
124 return out