Class |
Line # |
Actions |
|||||
---|---|---|---|---|---|---|---|
Context | 55 | 65 | 0% | 26 | 13 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | package org.devacfr.maven.skins.reflow.context; | |
20 | ||
21 | import javax.annotation.Nonnull; | |
22 | ||
23 | import java.io.IOException; | |
24 | import java.util.List; | |
25 | import java.util.Map; | |
26 | import java.util.Optional; | |
27 | ||
28 | import com.google.common.collect.ImmutableMap; | |
29 | import com.google.common.collect.Lists; | |
30 | import org.apache.commons.lang3.builder.ToStringBuilder; | |
31 | import org.codehaus.plexus.util.xml.Xpp3Dom; | |
32 | import org.devacfr.maven.skins.reflow.HtmlTool; | |
33 | import org.devacfr.maven.skins.reflow.ISkinConfig; | |
34 | import org.devacfr.maven.skins.reflow.model.Component; | |
35 | import org.devacfr.maven.skins.reflow.model.Footer; | |
36 | import org.devacfr.maven.skins.reflow.model.NavSideMenu; | |
37 | import org.devacfr.maven.skins.reflow.model.Navbar; | |
38 | import org.devacfr.maven.skins.reflow.model.ScrollTop; | |
39 | import org.devacfr.maven.skins.reflow.model.SideNavMenuItem; | |
40 | import org.devacfr.maven.skins.reflow.snippet.SnippetContext; | |
41 | import org.devacfr.maven.skins.reflow.snippet.SnippetParser; | |
42 | import org.slf4j.Logger; | |
43 | import org.slf4j.LoggerFactory; | |
44 | ||
45 | import static java.util.Objects.requireNonNull; | |
46 | ||
47 | /** | |
48 | * The base class of all contexts depending type of page. | |
49 | * | |
50 | * @author Christophe Friederich | |
51 | * @since 2.0 | |
52 | * @param <T> | |
53 | * type of inherrit context object. | |
54 | */ | |
55 | public abstract class Context<T extends Context<?>> extends Component { | |
56 | ||
57 | /** | |
58 | * map containing the equivalence of font awesome characters with image found in report pages. | |
59 | */ | |
60 | private static final Map<String, String> ICON_REPLACEMENTS = ImmutableMap.<String, String> builder() | |
61 | .put("img[src$=images/add.gif]", "<i class=\"fas fa-plus\"></i>") | |
62 | .put("img[src$=images/remove.gif]", "<i class=\"fas fa-minus\"></i>") | |
63 | .put("img[src$=images/fix.gif]", "<i class=\"fas fa-wrench\"></i>") | |
64 | .put("img[src$=images/update.gif]", "<i class=\"fas fa-redo\"></i>") | |
65 | .put("img[src$=images/icon_help_sml.gif]", "<i class=\"fas fa-question\"></i>") | |
66 | .put("img[src$=images/icon_success_sml.gif]", "<i class=\"fas fa-check-circle\"></i>") | |
67 | .put("img[src$=images/icon_warning_sml.gif]", "<i class=\"fas fa-exclamation-triangle\"></i>") | |
68 | .put("img[src$=images/icon_error_sml.gif]", "<i class=\"fas fa-exclamation-circle\"></i>") | |
69 | .put("img[src$=images/icon_info_sml.gif]", "<i class=\"fas fa-info\"></i>") | |
70 | .build(); | |
71 | ||
72 | /** */ | |
73 | private static final Logger LOGGER = LoggerFactory.getLogger(Context.class); | |
74 | ||
75 | /** */ | |
76 | private ContextType type; | |
77 | ||
78 | /** */ | |
79 | private final Navbar navbar; | |
80 | ||
81 | /** */ | |
82 | private final Footer footer; | |
83 | ||
84 | /** */ | |
85 | private final ScrollTop scrollTop; | |
86 | ||
87 | /** | |
88 | * Build a context depending of current type of page. | |
89 | * | |
90 | * @param config | |
91 | * a config (can not be {@code null}). | |
92 | * @return Returns a new instance of {@link Context} depending of current page. | |
93 | */ | |
94 | 17 | @Nonnull |
95 | public static Context<?> buildContext(@Nonnull final ISkinConfig config) { | |
96 | 17 | requireNonNull(config); |
97 | ||
98 | 17 | ContextType type = ContextType.page; |
99 | 17 | final List<SideNavMenuItem> allSideNaveMenuItems = NavSideMenu.findAllSideNavMenuItems(config); |
100 | 17 | if (LOGGER.isTraceEnabled()) { |
101 | 0 | LOGGER.trace("findAllSideNavMenuItems: " + allSideNaveMenuItems); |
102 | } | |
103 | 17 | final Xpp3Dom pageProperties = config.getPageProperties(); |
104 | 17 | final String fileId = config.getFileId(); |
105 | ||
106 | 17 | if (pageProperties != null) { |
107 | 10 | if (pageProperties.getAttribute("type") != null) { |
108 | 3 | type = ContextType.valueOf(pageProperties.getAttribute("type")); |
109 | } | |
110 | ||
111 | // frame type whether page associates to document page | |
112 | 10 | if (allSideNaveMenuItems.stream().filter(item -> fileId.equals(item.getSlugName())).count() > 0) { |
113 | 1 | type = ContextType.frame; |
114 | } | |
115 | } | |
116 | // if (type== null) { | |
117 | // type = ContextType.page; | |
118 | // } | |
119 | 17 | Context<?> context = null; |
120 | 17 | switch (type) { |
121 | 1 | case doc: |
122 | 1 | context = new DocumentContext(config); |
123 | 1 | break; |
124 | ||
125 | 1 | case frame: |
126 | // search the parent document page | |
127 | 1 | final Optional<SideNavMenuItem> menuItem = allSideNaveMenuItems.stream() |
128 | .filter(item -> fileId.equals(item.getSlugName())) | |
129 | .findFirst(); | |
130 | 1 | final SideNavMenuItem item = menuItem.get(); |
131 | 1 | final String documentParent = item.getParent(); |
132 | 1 | context = new FrameContext(config, documentParent); |
133 | 1 | break; |
134 | 2 | case body: |
135 | 2 | context = new BodyContext(config); |
136 | 2 | break; |
137 | 13 | case page: |
138 | 0 | default: |
139 | 13 | context = new PageContext(config); |
140 | 13 | break; |
141 | } | |
142 | 17 | return context; |
143 | } | |
144 | ||
145 | /** | |
146 | * Default constructor. | |
147 | * | |
148 | * @param config | |
149 | * a config (can not be {@code null}). | |
150 | * @param type | |
151 | * the type of context (can not be {@code null}). | |
152 | */ | |
153 | 17 | public Context(@Nonnull final ISkinConfig config, @Nonnull final ContextType type) { |
154 | 17 | requireNonNull(config); |
155 | 17 | this.withType(requireNonNull(type)); |
156 | 17 | this.navbar = new Navbar(config); |
157 | 17 | this.scrollTop = new ScrollTop(config); |
158 | 17 | this.footer = new Footer(config); |
159 | ||
160 | 17 | this.initialize(config); |
161 | ||
162 | // the ordering is important for execute preRender method | |
163 | 17 | this.addChildren(this.navbar, this.scrollTop, this.footer); |
164 | } | |
165 | ||
166 | /** | |
167 | * Allows to initialize the context. | |
168 | * | |
169 | * @param config | |
170 | * a config (can not be {@code null}). | |
171 | */ | |
172 | 15 | protected void initialize(@Nonnull final ISkinConfig config) { |
173 | // enable AnchorJS | |
174 | 15 | if (!config.not("anchorJS")) { |
175 | 15 | this.addCssOptions("anchorjs-enabled"); |
176 | } | |
177 | } | |
178 | ||
179 | /** | |
180 | * Allows to execute action before rendering of component. | |
181 | * | |
182 | * @param skinConfig | |
183 | * a config (can <b>not</b> be {@code null}). | |
184 | * @return Returns the {@link String} representing the transformed body content. | |
185 | * @since 2.1 | |
186 | */ | |
187 | 6 | public String preRender(@Nonnull final ISkinConfig skinConfig) { |
188 | 6 | return onPreRender(skinConfig, getBodyContent(skinConfig)); |
189 | } | |
190 | ||
191 | 5 | @Override |
192 | protected String onPreRender(final @Nonnull ISkinConfig skinConfig, final @Nonnull String bodyContent) { | |
193 | 5 | final HtmlTool htmlTool = getHtmlTool(skinConfig); |
194 | 5 | String content = bodyContent; |
195 | 5 | if (!skinConfig.not("imgLightbox")) { |
196 | // lightbox is enabled by default, so check for false and negate | |
197 | 5 | content = htmlTool.setAttr(content, |
198 | "a[href$=jpg], a[href$=JPG], a[href$=jpeg], a[href$=JPEG], " | |
199 | + "a[href$=png], a[href$=gif],a[href$=bmp]:has(img)", | |
200 | "data-lightbox", | |
201 | "page"); | |
202 | } | |
203 | ||
204 | 5 | if (!skinConfig.not("html5Anchor")) { |
205 | // HTML5-style anchors are enabled by default, so check for false and negate | |
206 | 5 | content = htmlTool.headingAnchorToId(content); |
207 | } | |
208 | ||
209 | 5 | if (!skinConfig.not("bootstrapCss")) { |
210 | // Bootstrap CSS class conversion is enabled by default, so check for false and | |
211 | // negate | |
212 | 5 | content = htmlTool |
213 | .addClass(content, "table.bodyTable", Lists.newArrayList("table", "table-striped", "table-hover")); | |
214 | // image is responsive by default | |
215 | 5 | content = htmlTool.addClass(content, "img", Lists.newArrayList("img-fluid")); |
216 | 5 | content = htmlTool.fixTableHeads(content); |
217 | } | |
218 | ||
219 | 5 | if (!skinConfig.not("bootstrapIcons")) { |
220 | // Bootstrap Icons are enabled by default, so check for false and negate | |
221 | 5 | content = htmlTool.replaceAll(content, ICON_REPLACEMENTS); |
222 | } | |
223 | ||
224 | // The <tt> tag is not supported in HTML5 (see | |
225 | // https://www.w3schools.com/tags/tag_tt.asp). | |
226 | 5 | content = htmlTool.replaceWith(content, "tt", "<code class=\"literal\">"); |
227 | 5 | return super.onPreRender(skinConfig, content); |
228 | } | |
229 | ||
230 | 0 | public String renderSnippets(final ISkinConfig skinConfig, final String bodyContent) throws IOException { |
231 | 0 | final SnippetContext snippetContext = new SnippetParser().parse(skinConfig, bodyContent); |
232 | 0 | return snippetContext.html(); |
233 | } | |
234 | ||
235 | /** | |
236 | * @return Returns the {@link Navbar}. | |
237 | */ | |
238 | 3 | public Navbar getNavbar() { |
239 | 3 | return navbar; |
240 | } | |
241 | ||
242 | /** | |
243 | * @return Returns the {@link ScrollTop}. | |
244 | */ | |
245 | 3 | public ScrollTop getScrollTop() { |
246 | 3 | return scrollTop; |
247 | } | |
248 | ||
249 | /** | |
250 | * @return Returns the {@link Footer}. | |
251 | */ | |
252 | 3 | public Footer getFooter() { |
253 | 3 | return footer; |
254 | } | |
255 | ||
256 | /** | |
257 | * Sets the type of context. | |
258 | * | |
259 | * @param type | |
260 | * the of context. | |
261 | * @return Returns the fluent instance context. | |
262 | */ | |
263 | 17 | protected T withType(final ContextType type) { |
264 | 17 | this.type = type; |
265 | 17 | return self(); |
266 | } | |
267 | ||
268 | /** | |
269 | * @return Returns the type of context of page. | |
270 | */ | |
271 | 2 | public String getType() { |
272 | 2 | return type.name(); |
273 | } | |
274 | ||
275 | /** | |
276 | * @return Returns the fluent instance. | |
277 | */ | |
278 | 17 | @SuppressWarnings("unchecked") |
279 | protected T self() { | |
280 | 17 | return (T) this; |
281 | } | |
282 | ||
283 | /** | |
284 | * {@inheritDoc} | |
285 | */ | |
286 | 0 | @Override |
287 | public String toString() { | |
288 | 0 | return ToStringBuilder.reflectionToString(this); |
289 | } | |
290 | } |