/* * Copyright (C) 2004-2008 Jive Software. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.admin; import org.jivesoftware.util.StringUtils; import org.dom4j.Element; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.http.HttpServletRequest; import java.util.Collection; import java.util.Iterator; import java.io.IOException; /** * <p>A simple JSP tag for displaying sidebar information in the admin console. The * {@link TabsTag} is similiar to this one.</p> * * <p>Attributes: <ul> * <li><tt>bean</tt> (required) - the id of the request attribute which is a * {@link AdminPageBean} instance. This class holds information * needed to properly render the admin console sidebar.</li> * <li><tt>css</tt> (optional) - the CSS class name used to decorate the LI of the sidebar items.</li> * <li><tt>currentcss</tt> (optional) - the CSS class name used to decorate the LI of the * currently selected sidebar item.</li> * <li><tt>heaadercss</tt> (optional) - the CSS class name used to decorate the LI of the header * section.</li></ul> * * <p>This class assumes there is a request attribute with the name specified by the bean attribute.</p> * * <p>This tag prints out minimal HTML. It basically prints an unordered list (UL element) with each * LI containing an "A" tag specfied by the body content of this tag. For example, the body should contain * a template A tag which will have its values replaced at runtime: <pre><tt> * * <jive:sidebar bean="jivepageinfo"> <br> *    <a href="[url]" title="[description]">[name]</a> <br> *    <jive:subsidebar> ... </jive:subsidebar> <br> * </jive:sidebar></tt></pre> * * There is a subsidebar tag for rendering the sub-sidebars. For more info, see the * {@link SubSidebarTag} class. * * <p>Available tokens for the "A" tag are:</p> <ul> * <li><tt>[id]</tt> - the ID of the sidebar item, usually not needed.</li> * <li><tt>[name]</tt> - the name of the sidebar item, should be thought of as the display name.</li> * <li><tt>[url]</tt> - the URL of the sidebar item.</li> * <li><tt>[description]</tt> - the description of the sidebar item, good for mouse rollovers.</li></ul> */ public class SidebarTag extends BodyTagSupport { private String css; private String currentcss; private String headercss; private SubSidebarTag subsidebarTag; /** * Returns the value of the CSS class to be used for tab decoration. If not set will return a blank string. */ public String getCss() { return clean(css); } /** * Sets the CSS used for tab decoration. */ public void setCss(String css) { this.css = css; } /** * Returns the value of the CSS class to be used for the currently selected LI (tab). If not set will * return a blank string. */ public String getCurrentcss() { return clean(currentcss); } /** * Sets the CSS class value for the currently selected tab. */ public void setCurrentcss(String currentcss) { this.currentcss = currentcss; } /** * Returns the value of the CSS class to be used for sidebar header sections. */ public String getHeadercss() { return headercss; } /** * Sets the CSS value used for the sidebar header sections. */ public void setHeadercss(String headercss) { this.headercss = headercss; } /** * Returns the subsidebar tag - should be declared in the body of this tag (see class description). */ public SubSidebarTag getSubsidebarTag() { return subsidebarTag; } /** * Sets the subsidebar tag - used by the container. */ public void setSubSidebar(SubSidebarTag subsidebarTag) { this.subsidebarTag = subsidebarTag; } /** * Does nothing, returns {@link #EVAL_BODY_BUFFERED} always. */ @Override public int doStartTag() throws JspException { return EVAL_BODY_BUFFERED; } /** * Gets the {@link AdminPageBean} instance from the request. If it doesn't exist then execution is stopped * and nothing is printed. If it exists, retrieve values from it and render the sidebar items. The body content * of the tag is assumed to have an A tag in it with tokens to replace (see class description) as well * as having a subsidebar tag.. * * @return {@link #EVAL_PAGE} after rendering the tabs. * @throws JspException if an exception occurs while rendering the sidebar items. */ @Override public int doEndTag() throws JspException { // Start by getting the request from the page context HttpServletRequest request = (HttpServletRequest)pageContext.getRequest(); // Check for body of this tag and the child tag if (getBodyContent().getString() == null) { throw new JspException("Error, no template (body value) set for the sidebar tag."); } if (subsidebarTag.getBody() == null) { throw new JspException("Error, no template (body value) set for the subsidebar tag"); } // Get the initial subpage and page IDs String subPageID = (String)request.getAttribute("subPageID"); String pageID = (String)request.getAttribute("pageID"); //String subnavID = (String)request.getAttribute("subnavID"); // If the pageID is null, use the subPageID to set it. If both the pageID and // subPageIDs are null, return because these are key to execution of the tag. if (subPageID != null || pageID != null) { if (pageID == null) { Element subPage = AdminConsole.getElemnetByID(subPageID); pageID = subPage.getParent().getParent().attributeValue("id"); } // Top level menu items if (AdminConsole.getModel().elements().size() > 0) { JspWriter out = pageContext.getOut(); StringBuilder buf = new StringBuilder(); Element current = null; Element subcurrent = null; Element subnav = null; if (subPageID != null) { subcurrent = AdminConsole.getElemnetByID(subPageID); } current = AdminConsole.getElemnetByID(pageID); if (current != null) { subnav = current.getParent(); } Element currentTab = (Element)AdminConsole.getModel().selectSingleNode( "//*[@id='" + pageID + "']/ancestor::tab"); boolean isSubmenu = false; if (subcurrent != null) { isSubmenu = subcurrent.getParent().getParent().getName().equals("item"); } // Loop through all items in the root, print them out if (currentTab != null && subnav != null) { Element sidebar = subnav.getParent().getParent(); //String header = sidebar.attributeValue("name"); String pluginName = sidebar.attributeValue("plugin"); // Print the header: String hcss = getHeadercss(); if (hcss == null) { hcss = ""; } Collection items = subnav.elements(); if (items.size() > 0) { buf.append("<ul>"); // Now print all items: for (Object itemObj : items) { Element item = (Element)itemObj; String subitemID = item.attributeValue("id"); String subitemName = item.attributeValue("name"); String subitemURL = item.attributeValue("url"); String subitemDescr = item.attributeValue("description"); pluginName = item.attributeValue("plugin"); String value = getBodyContent().getString(); if (value != null) { value = StringUtils.replace(value, "[id]", clean(subitemID)); value = StringUtils.replace(value, "[name]", clean(AdminConsole.getAdminText(subitemName, pluginName))); value = StringUtils.replace(value, "[description]", clean(AdminConsole.getAdminText(subitemDescr, pluginName))); value = StringUtils.replace(value, "[url]", request.getContextPath() + "/" + clean(subitemURL)); } String css = getCss(); boolean isCurrent = item.equals(current); boolean showSubmenu = subPageID != null; if (isCurrent && !showSubmenu) { css = getCurrentcss(); } buf.append("<li class=\"").append(css).append("\">").append(value).append("</li>"); // Print out a submenu if one exists: if (isSubmenu && isCurrent) { // Get the parent of the current item so we can get its // items - those will be siblings of the current item: Iterator siblings = subcurrent.getParent().elementIterator(); boolean hadNext = siblings.hasNext(); if (hadNext) { // Print out beginning UL buf.append("<li class=\"\"><ul class=\"subitems\">\n"); // Print the header LI String subheader = subcurrent.getParent().attributeValue("name"); pluginName = subcurrent.getParent().attributeValue("plugin"); buf.append("<li class=\"").append(hcss).append("\">").append( clean(AdminConsole.getAdminText(subheader, pluginName))).append("</li>"); } String extraParams = (String)request.getAttribute("extraParams"); while (siblings.hasNext()) { Element sibling = (Element)siblings.next(); String sibID = sibling.attributeValue("id"); String sibName = sibling.attributeValue("name"); String sibDescr = sibling.attributeValue("description"); String sibURL = sibling.attributeValue("url"); pluginName = sibling.attributeValue("plugin"); if (extraParams != null) { sibURL += ((sibURL.indexOf('?') > -1 ? "&" : "?") + extraParams); } boolean isSubCurrent = sibling.equals(subcurrent); String subcss = getCss(); if (isSubCurrent) { subcss = getCurrentcss(); } String svalue = getSubsidebarTag().getBody(); if (svalue != null) { svalue = StringUtils.replace(svalue, "[id]", clean(sibID)); svalue = StringUtils.replace(svalue, "[name]", clean(AdminConsole.getAdminText(sibName, pluginName))); svalue = StringUtils.replace(svalue, "[description]", clean(AdminConsole.getAdminText(sibDescr, pluginName))); svalue = StringUtils.replace(svalue, "[url]", request.getContextPath() + "/" + clean(sibURL)); } buf.append("<li class=\"").append(subcss).append("\">").append(svalue).append("</li>\n"); } if (hadNext) { // Print out ending UL buf.append("</ul></li>\n"); } } } buf.append("</ul>"); try { out.write(buf.toString()); } catch (IOException e) { throw new JspException(e); } } } } } return EVAL_PAGE; } /** * Cleans the given string - if it's null, it's converted to a blank string. If it has ' then those are * converted to double ' so HTML isn't screwed up. * * @param in the string to clean * @return a cleaned version - not null and with escaped characters. */ private String clean(String in) { return (in == null ? "" : StringUtils.replace(in, "'", "\\'")); } }