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