1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.devacfr.maven.skins.reflow.snippet;
20
21 import javax.annotation.Nonnull;
22 import javax.annotation.Nullable;
23
24 import java.util.Map;
25 import java.util.stream.Collectors;
26
27 import com.google.common.base.MoreObjects;
28 import com.google.common.collect.Maps;
29 import org.devacfr.maven.skins.reflow.snippet.ComponentToken.Type;
30 import org.jsoup.nodes.Attribute;
31 import org.jsoup.nodes.Attributes;
32 import org.jsoup.nodes.Element;
33 import org.jsoup.nodes.Node;
34 import org.jsoup.nodes.TextNode;
35 import org.jsoup.parser.Tag;
36
37 import static java.util.Objects.requireNonNull;
38
39
40
41
42
43
44
45
46
47 public class Component<T extends Component<T>> {
48
49
50 private final Map<String, String> attributes = Maps.newHashMap();
51
52
53 private Component<?> parent;
54
55
56 private final Components children = new Components();
57
58
59 private final Map<String, Components> childrenMap = Maps.newHashMap();
60
61
62 private final Node node;
63
64
65
66
67
68
69 public static Component<?> createComponent(@Nonnull final Node node, final Component<?> parent) {
70 return new Component<>(node).withParent(parent).addAttributes(node.attributes());
71 }
72
73
74
75
76 protected Component(@Nonnull final Node node) {
77 this.node = requireNonNull(node);
78 }
79
80
81
82
83 public String getName() {
84 return node.nodeName();
85 }
86
87
88
89
90 @Nonnull
91 Type getInternalType() {
92 return getRootParent().getType();
93 }
94
95
96
97
98 public boolean isHtmlTag() {
99 return node instanceof TextNode || Tag.isKnownTag(node.nodeName());
100 }
101
102
103
104
105 public String getHtml() {
106 if (!isHtmlTag()) {
107 if (children.isEmpty()) {
108 return null;
109 } else {
110 return children.html();
111 }
112 } else {
113 return this.node.outerHtml();
114 }
115 }
116
117
118
119
120 public String getOwnHtml() {
121 if (!isHtmlTag()) {
122 return null;
123 } else {
124 return this.node.outerHtml();
125 }
126 }
127
128
129
130
131 public Component<?> getParent() {
132 return parent;
133 }
134
135 @Nullable protected Element getElement() {
136 if (this.node instanceof Element) {
137 return (Element) this.node;
138 }
139 return null;
140 }
141
142
143
144
145
146 public Object get(@Nonnull final String name) {
147 requireNonNull(name);
148 String key = name.toLowerCase();
149
150 if (this.attributes.containsKey(key)) {
151 return this.attributes.get(key);
152 } else {
153
154
155 if (key.endsWith("s") && !this.childrenMap.containsKey(key)) {
156 key = key.substring(0, key.length() - 1);
157 if (this.childrenMap.containsKey(key)) {
158 return this.childrenMap.get(key);
159 }
160 } else if (this.childrenMap.containsKey(key)) {
161 final Components value = this.childrenMap.get(key);
162
163 if (value.size() > 1) {
164 return value;
165 }
166 return value.first();
167 }
168 }
169 return null;
170 }
171
172 public Map<String, String> getAttrs() {
173 return this.attributes;
174 }
175
176
177
178
179 public Components getChildren() {
180 return children;
181 }
182
183 public Components getChildren(final String name) {
184 final String key = requireNonNull(name).toLowerCase();
185 if (this.childrenMap.containsKey(key)) {
186 return this.childrenMap.get(key);
187 }
188 return Components.empty();
189 }
190
191 public T addChild(final Component<?> component) {
192 final String key = component.getName();
193 Components value = null;
194 if (!this.childrenMap.containsKey(key)) {
195 value = new Components();
196 this.childrenMap.put(key, value);
197 } else {
198 value = this.childrenMap.get(key);
199 }
200 value.add(component);
201 this.children.add(component);
202 return self();
203 }
204
205 protected T withParent(final Component<?> parent) {
206 this.parent = parent;
207 return self();
208 }
209
210 @Nonnull
211 protected SnippetComponent<?> getRootParent() {
212 Component<?> parent = this.parent;
213 while (!(parent instanceof SnippetComponent<?>)) {
214 parent = parent.parent;
215 }
216 return (SnippetComponent<?>) parent;
217 }
218
219
220
221
222
223 protected T addAttributes(@Nonnull final Attributes attrs) {
224 attrs.asList().stream().forEach(this::addAttribute);
225 return self();
226 }
227
228
229
230
231
232 protected T addAttribute(@Nonnull final Attribute attr) {
233 this.attributes.put(requireNonNull(attr.getKey()).toLowerCase(), requireNonNull(attr.getValue()));
234 return self();
235 }
236
237
238
239
240 @SuppressWarnings("unchecked")
241 protected T self() {
242 return (T) this;
243 }
244
245
246
247
248 @Override
249 public String toString() {
250 return MoreObjects.toStringHelper(this)
251 .add("name", this.getName())
252 .add("isHtmlTag", this.isHtmlTag())
253 .add("attributes", this.attributes)
254 .add("children", this.children.stream().map((cpt) -> cpt.getName()).collect(Collectors.toList()))
255 .toString();
256 }
257 }