1. Project Clover database mar. janv. 20 2026 12:32:22 CET
  2. Package org.devacfr.maven.skins.reflow.model

File NavSideMenu.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart6.png
71% of files have more coverage

Code metrics

14
53
11
1
258
120
19
0,36
4,82
11
1,73

Classes

Class Line # Actions
63 53 0% 19 34
0.564102656,4%
 

Contributing tests

This file is covered by 22 tests. .

Source view

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 java.util.Objects.requireNonNull;
19   
20    import com.google.common.base.Strings;
21    import com.google.common.collect.Lists;
22    import java.util.ArrayList;
23    import java.util.Collections;
24    import java.util.List;
25    import javax.annotation.Nonnull;
26    import javax.annotation.Nullable;
27    import org.apache.commons.lang3.builder.ToStringBuilder;
28    import org.codehaus.plexus.util.xml.Xpp3Dom;
29    import org.devacfr.maven.skins.reflow.ISkinConfig;
30    import org.devacfr.maven.skins.reflow.SkinConfigTool;
31    import org.devacfr.maven.skins.reflow.Xpp3Utils;
32   
33    /**
34    * Represents the navside menu component used in document page.
35    * <p>
36    * A sample configuration would be like that:
37    * </p>
38    *
39    * <pre>
40    * {@code
41    * <custom>
42    * <reflowSkin>
43    * <pages>
44    * <document type="doc">
45    * <menu name="Documentation" selectFirstOnExpand="true">
46    * <item name="Get Started" href="get-started.html" />
47    * <item name="Layouts">
48    * <item name="Overview" href="layouts.html" />
49    * <item name="Body" href="body.html" />
50    * </item>
51    * <item name="Migration" href="migration.html" />
52    * </menu>
53    * </document>
54    * </pages>
55    * </reflowSkin>
56    * </custom>
57    * }∂
58    * </pre>
59    *
60    * @author Christophe Friederich
61    * @since 2.0
62    */
 
63    public class NavSideMenu extends BsComponent {
64   
65    /** */
66    private static final String COMPONENT = "navside-menu";
67   
68    /** */
69    private static final String MENU_COMPONENT = "menu";
70   
71    /** */
72    private String name;
73   
74    /** */
75    private List<SideNavMenuItem> items;
76   
77    /** */
78    private boolean selectFirstOnExpand = false;
79   
80    /**
81    * Find all {@link SideNavMenuItem sidenav menu items} declared in all document pages.
82    *
83    * @param config
84    * a config (can <b>not</b> be {@code null}).
85    * @return Returns a list of all all {@link SideNavMenuItem sidenav menu items} declared in all document pages
86    * (returns list can <b>not</b> be {@code null}).
87    */
 
88  22 toggle @Nonnull
89    public static List<SideNavMenuItem> findAllSideNavMenuItems(@Nonnull final ISkinConfig config) {
90  22 requireNonNull(config);
91  22 final Xpp3Dom pagesNode = Xpp3Utils.getFirstChild(config.getGlobalProperties(), "pages", config.getNamespace());
92  22 if (pagesNode == null) {
93  10 return Collections.emptyList();
94    }
95  12 final Xpp3Dom[] pages = pagesNode.getChildren();
96  12 final List<SideNavMenuItem> includePages = new ArrayList<>();
97  12 for (final Xpp3Dom page : pages) {
98  34 final String type = page.getAttribute("type");
99  34 if ("doc".equals(type)) {
100    // This allows preventing accidental reuse of child page in other module of
101    // project
102  12 final String projectId = page.getAttribute("project");
103  12 if (!Strings.isNullOrEmpty(projectId) && !projectId.equals(config.getProjectId())) {
104  0 continue;
105    }
106  12 final Xpp3Dom menu = page.getChild(MENU_COMPONENT);
107  12 if (menu == null) {
108  0 continue;
109    }
110  12 final String pageName = page.getName();
111    // create a flatten list containing all menuItem.
112  12 addMenuItemRecursively(includePages, config, menu, pageName, true);
113    }
114    }
115  12 return includePages;
116    }
117   
118    /**
119    * Default constructor.
120    *
121    * @param config
122    * a config (can <b>not</b> be {@code null}).
123    */
 
124  1 toggle public NavSideMenu(@Nonnull final ISkinConfig config) {
125  1 super(config, "navside");
126  1 requireNonNull(config);
127  1 final Xpp3Dom pageNode = config.getPageProperties();
128  1 final Xpp3Dom menu = pageNode.getChild(MENU_COMPONENT);
129  1 final List<SideNavMenuItem> items = Lists.newArrayList();
130  1 if (menu != null) {
131  0 final String pageName = pageNode.getName();
132  0 addMenuItemRecursively(items, config, menu, pageName, false);
133   
134  0 this.withName(menu.getAttribute("name"))
135    .withItems(items)
136    .withSelectFirstOnSelect(
137    config.getAttributeValue(MENU_COMPONENT, "selectFirstOnExpand", Boolean.class, true));
138  0 this.setTheme(config.getAttributeValue(COMPONENT, "theme", String.class, "light"));
139  0 this.setBackground(config.getAttributeValue(COMPONENT, "background", String.class, "light"));
140  0 this.setCssClass(config.getAttributeValue(COMPONENT, "cssClass", String.class, null));
141    }
142  1 this.addCssOptions("sidenav-enabled");
143  1 if (isSelectFirstOnExpand()) {
144  0 this.addCssOptions("sidenav-select-first-on-select");
145    }
146    }
147   
148    /**
149    * Gets the name of menu displayed on top of navside menu.
150    *
151    * @return Returns a {@link String} representing the name of menu.
152    */
 
153  0 toggle @Nullable public String getName() {
154  0 return name;
155    }
156   
157    /**
158    * Sets the name of menu displayed on top of navside menu.
159    *
160    * @param name
161    * the name to use.
162    * @return Returns the fluent instance.
163    */
 
164  0 toggle protected NavSideMenu withName(final String name) {
165  0 this.name = name;
166  0 return this;
167    }
168   
169    /**
170    * Gets the indicating whether menu contains a least one menu item.
171    *
172    * @return Returns {@code true} whether menu contains a least one menu item, otherwise returns {@code false}.
173    */
 
174  0 toggle public boolean isHasItems() {
175  0 return items != null && !items.isEmpty();
176    }
177   
178    /**
179    * @return Returns the {@link List} of {@link SideNavMenuItem} containing in {@code <menu> element}.
180    */
 
181  0 toggle @Nonnull
182    public List<SideNavMenuItem> getItems() {
183  0 return items;
184    }
185   
186    /**
187    * Sets the {@link List} of {@link SideNavMenuItem}.
188    *
189    * @param items
190    * list of items to use.
191    * @return Returns the fluent instance.
192    */
 
193  0 toggle protected NavSideMenu withItems(final List<SideNavMenuItem> items) {
194  0 this.items = items;
195  0 return this;
196    }
197   
198    /**
199    * Gets the indicating whether the first sub menu item should be selected when a dropdown menu item is selected and
200    * should expand.
201    *
202    * @return Returns {@code true} whether the first sub menu item should be selected when a dropdown menu item is
203    * selected and expanded, otherwise returns {@code false}.
204    */
 
205  1 toggle public boolean isSelectFirstOnExpand() {
206  1 return selectFirstOnExpand;
207    }
208   
209    /**
210    * Sets the indicating whether the first sub menu item should be selected when a dropdown menu item is selected and
211    * should expand.
212    *
213    * @param selectFirstOnExpand
214    * a value to use.
215    * @return Returns the fluent instance.
216    */
 
217  0 toggle protected NavSideMenu withSelectFirstOnSelect(final boolean selectFirstOnExpand) {
218  0 this.selectFirstOnExpand = selectFirstOnExpand;
219  0 return this;
220    }
221   
222    /**
223    * {@inheritDoc}
224    */
 
225  0 toggle @Override
226    public String toString() {
227  0 return ToStringBuilder.reflectionToString(this);
228    }
229   
230    /**
231    * @param menuItems
232    * @param parentNode
233    * @param pageName
234    * @param flatten
235    */
 
236  48 toggle private static void addMenuItemRecursively(@Nonnull final List<SideNavMenuItem> menuItems,
237    @Nonnull final ISkinConfig config,
238    @Nonnull final Xpp3Dom parentNode,
239    @Nonnull final String pageName,
240    final boolean flatten) {
241  48 for (final Xpp3Dom item : Xpp3Utils.getChildrenNodes(parentNode, "item")) {
242  36 final String href = item.getAttribute("href");
243  36 final SideNavMenuItem menuItem = new SideNavMenuItem().withName(item.getAttribute("name"))
244    .withParent(pageName)
245    .withHref(config.relativeLink(href))
246    .withSlugName(SkinConfigTool.slugFilename(href))
247    .withIcon(item.getAttribute("icon"));
248  36 menuItems.add(menuItem);
249  36 if (flatten) {
250  36 addMenuItemRecursively(menuItems, config, item, pageName, true);
251    } else {
252  0 final List<SideNavMenuItem> list = new ArrayList<>();
253  0 menuItem.withItems(list);
254  0 addMenuItemRecursively(list, config, item, pageName, false);
255    }
256    }
257    }
258    }