1 /*
2 * Copyright 2012-2025 Christophe Friederich
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.devacfr.maven.skins.reflow.model;
17
18 import static com.google.common.collect.FluentIterable.concat;
19 import static java.util.Objects.requireNonNull;
20
21 import com.google.common.base.Joiner;
22 import com.google.common.base.Strings;
23 import com.google.common.collect.FluentIterable;
24 import com.google.common.collect.Lists;
25 import java.util.List;
26 import javax.annotation.Nonnull;
27 import org.devacfr.maven.skins.reflow.ISkinConfig;
28
29 /**
30 * The abstract class of all component used in Reflow rendering.
31 *
32 * @author devacfr
33 * @since 2.0
34 */
35 public abstract class Component {
36
37 /** */
38 protected final ISkinConfig config;
39
40 /** */
41 private String cssClass;
42
43 /** */
44 private final List<String> cssOptions = Lists.newArrayList();
45
46 /** */
47 private final List<Component> children = Lists.newArrayList();
48
49 /**
50 * Constructor.
51 *
52 * @param config
53 * the current skin config.
54 */
55 protected Component(@Nonnull final ISkinConfig config) {
56 this.config = requireNonNull(config);
57 }
58
59 /**
60 * @return Returns a {@link String} representing the css classes to apply to component.
61 */
62 @Nonnull
63 public String getCssClass() {
64 if (Strings.isNullOrEmpty(cssClass)) {
65 return "";
66 }
67 return cssClass;
68 }
69
70 /**
71 * @param cssClass
72 * the cssClass to set
73 */
74 protected void setCssClass(final String cssClass) {
75 this.cssClass = cssClass;
76 }
77
78 /**
79 * Gets the css options associated to component. A css option is css class that can be set directly on the component
80 * or on {@code <body>} element as global state.
81 * <p>
82 * Used generally in association with javascript to adapt specific javascript action to current state of component.
83 * </p>
84 *
85 * @return Returns a {@link String} representing the css options associated to component.
86 */
87 @Nonnull
88 public final String getCssOptions() {
89 return concat(this.cssOptions, concat(FluentIterable.from(children).transform(component -> component.cssOptions)))
90 .join(Joiner.on(' '));
91 }
92
93 /**
94 * Add components to this component.
95 *
96 * @param components
97 * list of component
98 */
99 protected void addChildren(final Component... components) {
100 this.children.addAll(Lists.newArrayList(components));
101 }
102
103 /**
104 * Add cssOption to this component.
105 *
106 * @param cssOptions
107 * a css option.
108 */
109 protected final void addCssOptions(@Nonnull final String... cssOptions) {
110 this.cssOptions.addAll(Lists.newArrayList(cssOptions));
111 }
112
113 /**
114 * generic pre-rendering method executed on all components of context.
115 *
116 * @param bodyContent
117 * the current body content.
118 * @return Returns a {@code String} representing the transformed body content on pre-rendering.
119 */
120 protected String onPreRender(@Nonnull final String bodyContent) {
121 final StringBuilder str = new StringBuilder(bodyContent);
122 this.children.forEach(component -> {
123 final String content = str.toString();
124 str.setLength(0);
125 str.append(component.onPreRender(content));
126 });
127 return str.toString();
128 }
129
130 }