KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > info > magnolia > cms > taglibs > util > SimpleNavigationTag


1 /**
2  *
3  * Magnolia and its source-code is licensed under the LGPL.
4  * You may copy, adapt, and redistribute this file for commercial or non-commercial use.
5  * When copying, adapting, or redistributing this document in keeping with the guidelines above,
6  * you are required to provide proper attribution to obinary.
7  * If you reproduce or distribute the document without making any substantive modifications to its content,
8  * please use the following attribution line:
9  *
10  * Copyright 1993-2005 obinary Ltd. (http://www.obinary.com) All rights reserved.
11  *
12  */

13 package info.magnolia.cms.taglibs.util;
14
15 import info.magnolia.cms.core.Content;
16 import info.magnolia.cms.core.ContentHandler;
17 import info.magnolia.cms.core.ItemType;
18 import info.magnolia.cms.util.Resource;
19
20 import java.io.IOException JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25
26 import javax.jcr.RepositoryException;
27 import javax.servlet.http.HttpServletRequest JavaDoc;
28 import javax.servlet.jsp.JspException JavaDoc;
29 import javax.servlet.jsp.JspWriter JavaDoc;
30 import javax.servlet.jsp.tagext.TagSupport JavaDoc;
31
32 import org.apache.commons.lang.StringEscapeUtils;
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.commons.lang.exception.NestableRuntimeException;
35 import org.apache.log4j.Logger;
36
37
38 /**
39  * Draws a simple, css based, navigation menu. The menu layout can then be customized using css, and the default menu
40  * should be enough for most uses. Two following page properties will also be used in the menu:
41  * <ul>
42  * <li><code>navTitle</code>: a title to use for the navigation menu, if different from the real page title</li>
43  * <li><code>accessKey</code>: an optional access key which will be added to the link</li>
44  * </ul>
45  *
46  * <pre>
47  * &lt;cmsu:simpleNavigation startLevel="3" />
48  * </pre>
49  *
50  * Will output the following:
51  *
52  * <pre>
53  * &lt;ul class="level3">
54  * &lt;li>&lt;a HREF="...">page 1 name &lt;/a>&lt;/li>
55  * &lt;li>&lt;a HREF="...">page 2 name &lt;/a>&lt;/li>
56  * &lt;li>&lt;strong>&lt;a HREF="...">selected page name &lt;/a>&lt;/strong>
57  * &lt;ul class="level3">
58  * &lt;li>&lt;a HREF="...">subpage 1 name &lt;/a>&lt;/li>
59  * &lt;li>&lt;a HREF="...">subpage 2 name &lt;/a>&lt;/li>
60  * &lt;li>&lt;a HREF="...">subpage 3 name &lt;/a>&lt;/li>
61  * &lt;/ul>
62  * &lt;/li>
63  * &lt;li>&lt;a HREF="...">page 4 name &lt;/a>&lt;/li>
64  * &lt;/ul>
65  * </pre>
66  *
67  * @author Fabrizio Giustina
68  * @version $Revision: $ ($Author: $)
69  */

70 public class SimpleNavigationTag extends TagSupport JavaDoc {
71
72     /**
73      * Page property: navigation title.
74      */

75     private static final String JavaDoc NODEDATA_NAVIGATIONTITLE = "navTitle"; //$NON-NLS-1$
76

77     /**
78      * Page property: access key.
79      */

80     public static final String JavaDoc NODEDATA_ACCESSKEY = "accessKey"; //$NON-NLS-1$
81

82     /**
83      * Default name for "open menu" nodeData.
84      */

85     public static final String JavaDoc DEFAULT_OPENMENU_NODEDATA = "openMenu"; //$NON-NLS-1$
86

87     /**
88      * Default name for "hide in nav" nodeData.
89      */

90     public static final String JavaDoc DEFAULT_HIDEINNAV_NODEDATA = "hideInNav"; //$NON-NLS-1$
91

92     /**
93      * Stable serialVersionUID.
94      */

95     private static final long serialVersionUID = 222L;
96
97     /**
98      * Logger.
99      */

100     private static Logger log = Logger.getLogger(SimpleNavigationTag.class);
101
102     /**
103      * Start level.
104      */

105     private int startLevel;
106
107     /**
108      * End level
109      */

110     private int endLevel;
111
112     /**
113      * Name for the "hide in nav" nodeData.
114      */

115     private String JavaDoc hideInNav;
116
117     /**
118      * Name for the "open menu" nodeData.
119      */

120     private String JavaDoc openMenu;
121
122     /**
123      * Style to apply to the menu
124      */

125     private String JavaDoc style;
126
127     /**
128      * Expand all the nodes (sitemap mode)
129      */

130     private boolean expandAll;
131
132     /**
133      * Setter for the <code>startLevel</code> tag attribute.
134      * @param startLevel the start level for navigation, defaults to <code>0</code>.
135      */

136     public void setStartLevel(int startLevel) {
137         this.startLevel = startLevel;
138     }
139
140     /**
141      * Setter for the <code>endLevel</code> tag attribute.
142      * @param endLevel the end level for navigation, defaults to not used if not set
143      */

144     public void setEndLevel(int endLevel) {
145         this.endLevel = endLevel;
146     }
147
148     /**
149      * Setter for the <code>style</code> tag attribute.
150      * @param style to apply to this menu, default is empty and not used
151      */

152     public void setStyle(String JavaDoc style) {
153         this.style = style;
154     }
155
156     /**
157      * Setter for <code>hideInNav</code> tag attribute.
158      * @param hideInNav name for the "hide in nav" nodeData.
159      */

160     public void setHideInNav(String JavaDoc hideInNav) {
161         this.hideInNav = hideInNav;
162     }
163
164     /**
165      * Setter for <code>openMenu</code> tag attribute.
166      * @param openMenu name for the "open menu" nodeData.
167      */

168     public void setOpenMenu(String JavaDoc openMenu) {
169         this.openMenu = openMenu;
170     }
171
172     /**
173      * @param expandAll The expandAll to set.
174      */

175     public void setExpandAll(boolean expandAll) {
176         this.expandAll = expandAll;
177     }
178
179     /**
180      * @see javax.servlet.jsp.tagext.Tag#doEndTag()
181      */

182     public int doEndTag() throws JspException JavaDoc {
183         Content activePage = Resource.getActivePage((HttpServletRequest JavaDoc) this.pageContext.getRequest());
184         JspWriter JavaDoc out = this.pageContext.getOut();
185         try {
186             if (style != null) {
187                 out.println("<span class=\"" + style + "\">"); //$NON-NLS-1$ //$NON-NLS-2$
188
}
189             drawChildren(activePage.getAncestor(this.startLevel), activePage, out);
190             if (style != null) {
191                 out.println("</span>"); //$NON-NLS-1$
192
}
193         }
194         catch (RepositoryException e) {
195             log.error("RepositoryException caught while drawing navigation: " + e.getMessage(), e); //$NON-NLS-1$
196
return EVAL_PAGE;
197         }
198         catch (IOException JavaDoc e) {
199             // should never happen
200
throw new NestableRuntimeException(e);
201         }
202         return EVAL_PAGE;
203     }
204
205     /**
206      * @see javax.servlet.jsp.tagext.Tag#release()
207      */

208     public void release() {
209         this.startLevel = 0;
210         this.hideInNav = null;
211         this.openMenu = null;
212         super.release();
213     }
214
215     /**
216      * Draws page children as an unordered list.
217      * @param page current page
218      * @param activePage active page
219      * @param out jsp writer
220      * @throws IOException jspwriter exception
221      * @throws RepositoryException any exception thrown during repository reading
222      */

223     private void drawChildren(Content page, Content activePage, JspWriter JavaDoc out) throws IOException JavaDoc, RepositoryException {
224
225         Collection JavaDoc children = page.getChildren(ItemType.CONTENT, ContentHandler.SORT_BY_SEQUENCE);
226
227         if (children.size() == 0) {
228             return;
229         }
230
231         if (startLevel > endLevel) {
232             endLevel = 0;
233         }
234
235         out.print("<ul class=\"level"); //$NON-NLS-1$
236
out.print(page.getLevel());
237         out.print("\">"); //$NON-NLS-1$
238

239         Iterator JavaDoc it = children.iterator();
240         while (it.hasNext()) {
241             Content child = (Content) it.next();
242
243             if (!expandAll) {
244                 if (child
245                     .getNodeData(StringUtils.defaultString(this.hideInNav, DEFAULT_HIDEINNAV_NODEDATA))
246                     .getBoolean()) {
247                     continue;
248                 }
249             }
250
251             List JavaDoc cssClasses = new ArrayList JavaDoc(3);
252
253             String JavaDoc title = child.getNodeData(NODEDATA_NAVIGATIONTITLE).getString(StringUtils.EMPTY);
254
255             // if nav title is not set, the main title is taken
256
if (StringUtils.isEmpty(title)) {
257                 title = child.getTitle();
258             }
259
260             // if main title is not set, the name of the page is taken
261
if (StringUtils.isEmpty(title)) {
262                 title = child.getName();
263             }
264
265             boolean showChildren;
266             boolean self = false;
267
268             if (expandAll) {
269                 showChildren = true;
270             }
271             else {
272
273                 if (activePage.getHandle().equals(child.getHandle())) {
274                     // self
275
showChildren = true;
276                     self = true;
277                     cssClasses.add("active"); //$NON-NLS-1$
278
}
279                 else {
280                     showChildren = (child.getLevel() <= activePage.getAncestors().size() && activePage.getAncestor(
281                         child.getLevel()).getHandle().equals(child.getHandle()));
282                 }
283
284                 if (!showChildren) {
285                     showChildren = child.getNodeData(
286                         StringUtils.defaultString(this.openMenu, DEFAULT_OPENMENU_NODEDATA)).getBoolean();
287                 }
288             }
289
290             if (endLevel > 0) {
291                 showChildren &= child.getLevel() < endLevel;
292             }
293
294             cssClasses.add(hasVisibleChildren(child) ? (showChildren ? "open" : "closed") : "leaf"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
295

296             StringBuffer JavaDoc css = new StringBuffer JavaDoc(cssClasses.size() * 10);
297             Iterator JavaDoc iterator = cssClasses.iterator();
298             while (iterator.hasNext()) {
299                 css.append(iterator.next());
300                 if (iterator.hasNext()) {
301                     css.append(" "); //$NON-NLS-1$
302
}
303             }
304
305             out.print("<li class=\""); //$NON-NLS-1$
306
out.print(css.toString());
307             out.print("\">"); //$NON-NLS-1$
308

309             if (self) {
310                 out.println("<strong>"); //$NON-NLS-1$
311
}
312
313             String JavaDoc accesskey = child.getNodeData(NODEDATA_ACCESSKEY).getString(StringUtils.EMPTY);
314
315             out.print("<a HREF=\""); //$NON-NLS-1$
316
out.print(((HttpServletRequest JavaDoc) this.pageContext.getRequest()).getContextPath());
317             out.print(child.getHandle());
318             out.print(".html\""); //$NON-NLS-1$
319

320             if (StringUtils.isNotEmpty(accesskey)) {
321                 out.print(" accesskey=\""); //$NON-NLS-1$
322
out.print(accesskey);
323                 out.print("\""); //$NON-NLS-1$
324
}
325
326             out.print(">"); //$NON-NLS-1$
327

328             out.print(StringEscapeUtils.escapeHtml(title));
329             out.print(" </a>"); //$NON-NLS-1$
330

331             if (self) {
332                 out.println("</strong>"); //$NON-NLS-1$
333
}
334
335             if (showChildren) {
336                 drawChildren(child, activePage, out);
337             }
338             out.print("</li>"); //$NON-NLS-1$
339
}
340
341         out.print("</ul>"); //$NON-NLS-1$
342
}
343
344     /**
345      * Checks if the page has a visible children. Pages with the <code>hide in nav</code> attribute set to
346      * <code>true</code> are ignored.
347      * @param page root page
348      * @return <code>true</code> if the given page has at least one visible child.
349      */

350     private boolean hasVisibleChildren(Content page) {
351         Iterator JavaDoc it = page.getChildren().iterator();
352         if (it.hasNext() && expandAll) {
353             return true;
354         }
355         while (it.hasNext()) {
356             Content ch = (Content) it.next();
357             if (!ch.getNodeData(StringUtils.defaultString(this.hideInNav, DEFAULT_HIDEINNAV_NODEDATA)).getBoolean()) {
358                 return true;
359             }
360         }
361         return false;
362     }
363
364 }
365
Popular Tags