Introduction
In the previous post (http://ben-bai.blogspot.tw/2012/07/jsp-custom-tag-body-tag.html), we have implemented a body tag 'fadeoutBlock', in this post we will try the advanced body tag - 'Nested Tags' and implement a tag set 'tabbox, tabpanel'.
Pre-define
1. A tabbox can contain several tabpanels.
2. You can set the 'width' and 'height' of a tabbox.
3. A tabpanel can contains any JSP body content.
4. You can set the 'header' of a tabpanel.
The Program
Tabbox.java
package test.tag.custom;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;
/**
* Simple tabbox with poor look and feel
*/
public class Tabbox extends BodyTagSupport {
private int _panelCnt = 0;
private int _width = 100;
private int _height = 100;
private StringBuilder _headerContent = new StringBuilder("");
private StringBuilder _bodyContent = new StringBuilder("");
public void setWidth (int width) {
_width = width;
}
public void setHeight (int height) {
_height = height;
}
public int doStartTag() throws JspException {
try {
// output the out most area
JspWriter out = pageContext.getOut();
out.print("<div");
out.print(" style=\"overflow: auto; width: "+_width+"px; height: "+_height+"px; border: 1px solid #CCCCCC;\"");
out.print(">");
} catch (Exception e) {
throw new JspException("Error: IOException while writing to client");
}
// evaluate body content and output it directly
return EVAL_BODY_INCLUDE;
}
public int doEndTag() throws JspException {
try {
JspWriter out = pageContext.getOut();
// output the header/body of tabpanels
out.print("<div>"+_headerContent.toString()+"</div>");
out.print("<div style=\"margin: 10px; border: 1px solid #3648AE;\">"+_bodyContent.toString()+"</div></div>");
} catch (Exception ex) {
throw new JspException(ex.getMessage());
}
release();
// continue evaluate page
return EVAL_PAGE;
}
public void release() {
// have to reset all field values since container may reuse this instance
_panelCnt = 0;
_width = 100;
_height = 100;
_headerContent.setLength(0);
_bodyContent.setLength(0);
}
public void addHeaderContent (String content) {
// called by Tabpanel, add header content
String style = _panelCnt == 0? "background-color: gray;" : "background-color: transparent;";
style += " margin-right: 5px; border: 1px solid #CCCCCC; border-bottom: 0px; cursor: pointer;";
_headerContent.append("<span onclick=\""+showMatchedPanel()+"\" style=\""+style+"\">")
.append(content)
.append("</span>");
}
public void addBodyContent (String content) {
// called by Tabpanel, add body contents
String style = _panelCnt == 0? "" : "display: none;";
_bodyContent.append("<div style=\""+style+"\">")
.append(content)
.append("</div>");
}
public void increaseCnt () {
// called by Tabpanel, tell Tabbox the number of tabpanel is increased
_panelCnt++;
}
// its better provided by a .js file
private String showMatchedPanel () {
// the javascript that executes while tabpanel's header clicked
StringBuilder cmd = new StringBuilder();
cmd.append("var headerContainer = this.parentNode,")
.append(" headerArray = headerContainer.childNodes,")
.append(" bodyContainer = headerContainer.nextSibling,")
.append(" bodyArray = bodyContainer.childNodes,")
.append(" ele, i, idx;")
.append("for (i = 0; i < headerArray.length; i++) {")
.append(" if ((ele = headerArray[i]) == this) {")
.append(" ele.style.backgroundColor = 'gray';")
.append(" idx = i;")
.append(" } else")
.append(" ele.style.backgroundColor = 'transparent';")
.append("}")
.append("for (i = 0; i < bodyArray.length; i++) {")
.append(" if (i == idx)")
.append(" bodyArray[i].style.display = 'block';")
.append(" else")
.append(" bodyArray[i].style.display = 'none';")
.append("}");
return cmd.toString();
}
}
Tabbox provide the API's for tabpanels to add their header/body content and then output them properly with the appropriate javascript action while header clicked.
Tabpanel.java
package test.tag.custom;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;
/**
* Simple tabpanel with poor look and feel
*/
public class Tabpanel extends BodyTagSupport {
private String _header = new String("tab header");
public void setHeader (String header) {
_header = header;
}
public int doStartTag() throws JspException {
// denotes evaluate body but do not output it, store it in buffer
return EVAL_BODY_BUFFERED;
}
public int doEndTag() throws JspException {
// find the parent tabbox
Tabbox parent = (Tabbox)findAncestorWithClass(this, Tabbox.class);
// get the buffered body content
String body = getBodyContent().getString();
// parent should not be null
if(parent == null)
throw new JspException("Tabpanel.doStartTag(): " + "No Tabbox ancestor");
// fix empty body
if (body == null || body.isEmpty())
body = " "; // at least a space char
// fix empty header
if (_header == null || _header.isEmpty())
_header = " "; // at least a space char
// add header content to parent tabbox
parent.addHeaderContent(_header);
// add body content to parent tabbox
parent.addBodyContent(body);
parent.increaseCnt();
release();
return EVAL_PAGE;
}
public void release() {
// have to reset all field values since container may reuse this instance
_header = null;
}
}
Tabpanel will store its body content in a buffer then pass it and header to Tabbox to render.
The tag definition
Add the fragment below to the tld file which already created from previous post (http://ben-bai.blogspot.tw/2012/06/jsp-custom-tag-simple-tag.html) then export jar as described in the previous post.
<tag>
<!-- tag name -->
<name>tabbox</name>
<!-- tag class path -->
<tagclass>test.tag.custom.Tabbox</tagclass>
<!-- denotes the tag has JSP body content -->
<bodycontent>JSP</bodycontent>
<attribute>
<!-- attribute name -->
<name>width</name>
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<!-- attribute name -->
<name>height</name>
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<tag>
<!-- tag name -->
<name>tabpanel</name>
<!-- tag class path -->
<tagclass>test.tag.custom.Tabpanel</tagclass>
<!-- denotes the tag has JSP body content -->
<bodycontent>JSP</bodycontent>
<attribute>
<!-- attribute name -->
<name>header</name>
<!-- required or not -->
<required>false</required>
<!-- el enable or not (true denotes can be eval at runtime) -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
Test Page
tabboxTest.jsp
<%@ page isErrorPage="true" language="java"
contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page isELIgnored ="false" %>
<!-- use the custom taglib with prefix ct -->
<%@taglib prefix="ct" uri="http://test.tag.custom/jsp/impl/taglib"%>
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8"/>
<title>EL Math Practice</title>
</head>
<body>
<!-- the tabbox -->
<ct:tabbox width="500" height="300">
<!-- child tabpanels -->
<ct:tabpanel header="Tab 1">
this is the first panel of the tabbox
<div style="height: 150px; width: 150px; background-color: red;"></div>
</ct:tabpanel>
<ct:tabpanel header="Tab 2">
<div style="height: 200px; width: 200px; background-color: green;">
second panel
</div>
</ct:tabpanel>
<ct:tabpanel header="Tab 3">
the third panel
</ct:tabpanel>
</ct:tabbox>
</body>
</html>
The Result
View the demo flash on line
http://screencast.com/t/e5QqxXQ1O
You can find the flash file at github:
https://github.com/benbai123/JSP_Servlet_Practice/blob/master/demo_src/JSP/Custom_tag/tabbox_test.swf
Reference
http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags.html
Download
The full project is at github
https://github.com/benbai123/JSP_Servlet_Practice/tree/master/Practice/CustomTagPractice
No comments:
Post a Comment