/** * This file Copyright (c) 2003-2008 Magnolia International * Ltd. (http://www.magnolia.info). All rights reserved. * * * This file is dual-licensed under both the Magnolia * Network Agreement and the GNU General Public License. * You may elect to use one or the other of these licenses. * * This file is distributed in the hope that it will be * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. * Redistribution, except as permitted by whichever of the GPL * or MNA you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or * modify this file under the terms of the GNU General * Public License, Version 3, as published by the Free Software * Foundation. You should have received a copy of the GNU * General Public License, Version 3 along with this program; * if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * 2. For the Magnolia Network Agreement (MNA), this file * and the accompanying materials are made available under the * terms of the MNA which accompanies this distribution, and * is available at http://www.magnolia.info/mna.html * * Any modifications to this file must keep this entire header * intact. * */ package info.magnolia.cms.taglibs.util; import info.magnolia.cms.core.Content; import info.magnolia.cms.core.ItemType; import info.magnolia.cms.core.NodeData; import info.magnolia.cms.i18n.I18nContentSupportFactory; import info.magnolia.cms.util.Resource; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.jcr.RepositoryException; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.exception.NestableRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Draws a simple, css based, navigation menu. The menu layout can then be customized using css, and the default menu * should be enough for most uses. Two following page properties will also be used in the menu: *
navTitle
: a title to use for the navigation menu, if different from the real page titleaccessKey
: an optional access key which will be added to the linkwrappingElement
: an optional html element (div, span, p, etc) to go within the tag wrapping the anchor text
* * <cmsu:simpleNavigation startLevel="3" style="mystyle"/> ** * Will output the following: * *
* <ul class="level3 mystyle"> * <li><a href="...">page 1 name </a></li> * <li><a href="...">page 2 name </a></li> * <li class="trail"><a href="...">page 3 name </a> * <ul class="level4"> * <li><a href="...">subpage 1 name </a></li> * <li><a href="...">subpage 2 name </a></li> * <li><strong><a href="...">selected page name </a></strong></li> * </ul> * </li> * <li><a href="...">page 4 name </a></li> * </ul> ** * @author Fabrizio Giustina * @version $Revision: 15436 $ ($Author: fgiust $) */ public class SimpleNavigationTag extends TagSupport { /** * Css class added to active page. */ private static final String CSS_LI_ACTIVE = "active"; /** * Css class added to ancestor of the active page. */ private static final String CSS_LI_TRAIL = "trail"; /** * Css class added to leaf pages. */ private static final String CSS_LI_LEAF = "leaf"; //$NON-NLS-1$ /** * Css class added to open trees. */ private static final String CSS_LI_CLOSED = "closed"; //$NON-NLS-1$ /** * Css class added to closed trees. */ private static final String CSS_LI_OPEN = "open"; //$NON-NLS-1$ /** * Page property: navigation title. */ private static final String NODEDATA_NAVIGATIONTITLE = "navTitle"; //$NON-NLS-1$ /** * Page property: access key. */ public static final String NODEDATA_ACCESSKEY = "accessKey"; //$NON-NLS-1$ /** * Default name for "open menu" nodeData. */ public static final String DEFAULT_OPENMENU_NODEDATA = "openMenu"; //$NON-NLS-1$ /** * Default name for "hide in nav" nodeData. */ public static final String DEFAULT_HIDEINNAV_NODEDATA = "hideInNav"; //$NON-NLS-1$ /** * Default name for "wrapperElement" nodeData. */ public static final String DEFAULT_WRAPPERELEMENT_NODEDATA = ""; //$NON-NLS-1$ /** * Expand all expand all the nodes */ public static final String EXPAND_ALL = "all"; /** * Expand all expand only page that should be displayed in navigation */ public static final String EXPAND_SHOW = "show"; /** * Do not use expand functions */ public static final String EXPAND_NONE = "none"; /** * Stable serialVersionUID. */ private static final long serialVersionUID = 223L; /** * Logger. */ private static Logger log = LoggerFactory.getLogger(SimpleNavigationTag.class); /** * Start level. */ private int startLevel; /** * End level */ private int endLevel; /** * Name for the "hide in nav" nodeData. */ private String hideInNav; /** * Name for the "open menu" nodeData. */ private String openMenu; /** * Style to apply to the menu */ private String style; /** * html element to wrap the anchortext. (i.e.
startLevel
tag attribute.
* @param startLevel the start level for navigation, defaults to 0
.
*/
public void setStartLevel(int startLevel) {
this.startLevel = startLevel;
}
/**
* Setter for the endLevel
tag attribute.
* @param endLevel the end level for navigation, defaults to not used if not set
*/
public void setEndLevel(int endLevel) {
this.endLevel = endLevel;
}
/**
* Setter for the style
tag attribute.
* @param style to apply to this menu, default is empty and not used
*/
public void setStyle(String style) {
this.style = style;
}
/**
* Setter for hideInNav
tag attribute.
* @param hideInNav name for the "hide in nav" nodeData.
*/
public void setHideInNav(String hideInNav) {
this.hideInNav = hideInNav;
}
/**
* Setter for openMenu
tag attribute.
* @param openMenu name for the "open menu" nodeData.
*/
public void setOpenMenu(String openMenu) {
this.openMenu = openMenu;
}
/**
* Setter for nofollow
.
* @param nofollow The nofollow to set.
*/
public void setNofollow(String nofollow) {
this.nofollow = nofollow;
}
/**
* @param expandAll The expandAll to set. If the value is different than EXPAND_SHOW
then the call
* expandAll is set to EXPAND_ALL
*/
public void setExpandAll(String expandAll) {
if (expandAll.equalsIgnoreCase(EXPAND_SHOW)) {
this.expandAll = expandAll;
}
else {
this.expandAll = EXPAND_ALL;
}
}
/**
* Setter for classProperty
tag attribute.
* @param classProperty name for a page property which will be written to the css class attribute.
*/
public void setClassProperty(String classProperty) {
this.classProperty = classProperty;
}
/**
* Setter for wrapperElement
tag attribute.
* @param wrapperElement name of an html element that will be included in the anchor, wrapping the anchortext
*/
public void setWrapperElement(String wrapperElement) {
this.wrapperElement = wrapperElement;
}
/**
* @see javax.servlet.jsp.tagext.Tag#doEndTag()
*/
public int doEndTag() throws JspException {
Content activePage = Resource.getCurrentActivePage();
JspWriter out = this.pageContext.getOut();
if (startLevel > endLevel) {
endLevel = 0;
}
try {
if (this.startLevel <= activePage.getLevel()) {
Content startContent = activePage.getAncestor(this.startLevel);
drawChildren(startContent, activePage, out);
}
}
catch (RepositoryException e) {
log.error("RepositoryException caught while drawing navigation: " + e.getMessage(), e); //$NON-NLS-1$
return EVAL_PAGE;
}
catch (IOException e) {
// should never happen
throw new NestableRuntimeException(e);
}
return EVAL_PAGE;
}
/**
* @see javax.servlet.jsp.tagext.Tag#release()
*/
public void release() {
this.startLevel = 0;
this.endLevel = 0;
this.hideInNav = null;
this.openMenu = null;
this.style = null;
this.classProperty = null;
this.expandAll = EXPAND_NONE;
this.nofollow = null;
super.release();
}
/**
* Draws page children as an unordered list.
* @param page current page
* @param activePage active page
* @param out jsp writer
* @throws IOException jspwriter exception
* @throws RepositoryException any exception thrown during repository reading
*/
private void drawChildren(Content page, Content activePage, JspWriter out) throws IOException, RepositoryException {
Collection children = page.getChildren(ItemType.CONTENT);
if (children.size() == 0) {
return;
}
out.print("hide in nav
attribute set to
* true
are ignored.
* @param page root page
* @return true
if the given page has at least one visible child.
*/
private boolean hasVisibleChildren(Content page) {
Iterator it = page.getChildren().iterator();
if (it.hasNext() && expandAll.equalsIgnoreCase(EXPAND_ALL)) {
return true;
}
while (it.hasNext()) {
Content ch = (Content) it.next();
if (!ch.getNodeData(StringUtils.defaultString(this.hideInNav, DEFAULT_HIDEINNAV_NODEDATA)).getBoolean()) {
return true;
}
}
return false;
}
}