Return-Path: Delivered-To: apmail-incubator-jspwiki-commits-archive@minotaur.apache.org Received: (qmail 538 invoked from network); 23 Feb 2009 05:19:20 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 23 Feb 2009 05:19:20 -0000 Received: (qmail 34275 invoked by uid 500); 23 Feb 2009 05:19:20 -0000 Delivered-To: apmail-incubator-jspwiki-commits-archive@incubator.apache.org Received: (qmail 34259 invoked by uid 500); 23 Feb 2009 05:19:20 -0000 Mailing-List: contact jspwiki-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: jspwiki-dev@incubator.apache.org Delivered-To: mailing list jspwiki-commits@incubator.apache.org Received: (qmail 34250 invoked by uid 99); 23 Feb 2009 05:19:20 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 22 Feb 2009 21:19:20 -0800 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 23 Feb 2009 05:19:19 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 540BD23888A3; Mon, 23 Feb 2009 05:18:59 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r746883 - in /incubator/jspwiki/trunk/src/java/org/apache/wiki/tags: TabTag.java TabbedSectionTag.java Date: Mon, 23 Feb 2009 05:18:58 -0000 To: jspwiki-commits@incubator.apache.org From: ajaquith@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090223051859.540BD23888A3@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: ajaquith Date: Mon Feb 23 05:18:58 2009 New Revision: 746883 URL: http://svn.apache.org/viewvc?rev=746883&view=rev Log: Re-wrote TabbedSectionTab and TabTag so that they operate across included or nested JSPs. Modified: incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabTag.java incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabbedSectionTag.java Modified: incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabTag.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabTag.java?rev=746883&r1=746882&r2=746883&view=diff ============================================================================== --- incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabTag.java (original) +++ incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabTag.java Mon Feb 23 05:18:58 2009 @@ -21,19 +21,17 @@ package org.apache.wiki.tags; -import java.util.Locale; - import javax.servlet.jsp.JspTagException; -import org.apache.wiki.i18n.InternationalizationManager; +import org.apache.wiki.tags.TabbedSectionTag.TabCollection; import org.apache.wiki.util.TextUtil; - /** *

- * Generates single tabbed page layout. Works together with the tabbedSection - * javascript. Note that if you do not specify an url, the body contents of the - * tag are loaded by the tag itself. + * Generates single tabbed page layout, when nested under a + * {@link TabbedSection} tag. Works together with the tabbedSection javascript. + * Note that if you do not specify an url, the body contents of the tag are + * loaded by the tag itself. *

*

* Attributes @@ -63,64 +61,135 @@ public class TabTag extends WikiTagBase { private static final long serialVersionUID = -8534125226484616489L; - - private String m_accesskey; - - private String m_outputTitle; - - private String m_tabTitle; - - private String m_tabTitleKey; - - private String m_url; + + private final TabInfo m_tabInfo = new TabInfo(); /** - * {@inheritDoc} + * Lightweight class that holds information about TabTags. */ - public int doEndTag() throws javax.servlet.jsp.JspTagException + public static class TabInfo { - TabbedSectionTag parent = getParentTag( TabbedSectionTag.class ); - - StringBuilder sb = new StringBuilder(); - - if( parent.isStateFindDefaultTab() ) + private String m_id = null; + + private String m_accesskey = null; + + private String m_tabTitle = null; + + private String m_tabTitleKey = null; + + private String m_url = null; + + /** + * Sets the id. + * @param id + */ + public void setId( String id ) + { + m_id = id; + } + + /** + * Sets the tab access key. + * + * @param accessKey the access key + */ + public void setAccesskey( String accessKey ) + { + m_accesskey = TextUtil.replaceEntities( accessKey ); // take only the + // first char + } + + /** + * Sets the tab title. + * + * @param title the tab title + */ + public void setTitle( String title ) + { + m_tabTitle = TextUtil.replaceEntities( title ); + } + + /** + * Sets the tab title key. + * + * @param key the tab title key + */ + public void setTitleKey( String key ) + { + m_tabTitleKey = TextUtil.replaceEntities( key ); + } + + /** + * Sets the tab URL. + * + * @param url the URL + */ + public void setUrl( String url ) + { + m_url = TextUtil.replaceEntities( url ); + } + + /** + * Returns the ID for this tab. + * @return + */ + public String getId() + { + return m_id; + } + + /** + * Returns the URL for this tab, if supplied. + * + * @return the URL + */ + public String getUrl() + { + return m_url; + } + + /** + * Returns the tab access key. + * + * @return the access key + */ + public String getAccesskey() + { + return m_accesskey; + } + + /** + * Returns the tab title. + * @return the title + */ + public String getTitle() + { + return m_tabTitle; + } + + /** + * Returns the i18n key used to generate the tab title. + * @return the title key + */ + public String getTitleKey() { - // inform the parent of each tab - parent.validateDefaultTab( getId() ); - } - else if( parent.isStateGenerateTabBody() ) - { - sb.append( "\n" ); - } - else if( parent.isStateGenerateTabMenu() ) - { - sb.append( "" ); - sb.append( m_outputTitle ); - sb.append( "" ); + return m_tabTitleKey; } + } + protected TabInfo getTabInfo() + { + return m_tabInfo; + } + + /** + * {@inheritDoc} + */ + public int doEndTag() throws javax.servlet.jsp.JspTagException + { try { - pageContext.getOut().write( sb.toString() ); + pageContext.getOut().write( "\n" ); } catch( java.io.IOException e ) { @@ -136,12 +205,10 @@ public void doFinally() { super.doFinally(); - - m_accesskey = null; - m_outputTitle = null; - m_tabTitle = null; - m_tabTitleKey = null; - m_url = null; + m_tabInfo.m_accesskey = null; + m_tabInfo.m_tabTitle = null; + m_tabInfo.m_tabTitleKey = null; + m_tabInfo.m_url = null; } /** @@ -149,8 +216,6 @@ */ public int doWikiStartTag() throws JspTagException { - TabbedSectionTag parent = getParentTag( TabbedSectionTag.class ); - // // Sanity checks // @@ -158,43 +223,22 @@ { throw new JspTagException( "Tab Tag without \"id\" attribute" ); } - if( m_tabTitle == null && m_tabTitleKey == null ) + if( m_tabInfo.m_tabTitle == null && m_tabInfo.m_tabTitleKey == null ) { throw new JspTagException( "Tab Tag without \"tabTitle\" or \"tabTitleKey\" attribute" ); } - if( parent == null ) - { - throw new JspTagException( "Tab Tag without parent \"TabbedSection\" Tag" ); - } - - // Generate the actual title - if( m_tabTitleKey != null ) - { - Locale locale = m_wikiContext.getHttpRequest().getLocale(); - InternationalizationManager i18n = m_wikiContext.getEngine().getInternationalizationManager(); - m_outputTitle = i18n.get( InternationalizationManager.TEMPLATES_BUNDLE, locale, m_tabTitleKey ); - } - if ( m_outputTitle == null ) - { - m_outputTitle = m_tabTitle; - } - - if( !parent.isStateGenerateTabBody() ) - return SKIP_BODY; - - StringBuilder sb = new StringBuilder( 32 ); - - sb.append( "

\n" ); + // Add tab to TabCollection so parent TabbedSection can get it later + TabCollection tc = TabbedSectionTag.getTabContext( getPageContext().getRequest() ); + tc.addTab( this ); + // Generate the opening
tag, always with "hidetab" class + // (TabbedSection#doAfterBody will fix this later...) try { - pageContext.getOut().write( sb.toString() ); + pageContext.getOut().write( "
\n" ); } catch( java.io.IOException e ) { @@ -203,7 +247,17 @@ return EVAL_BODY_INCLUDE; } - + + /** + * {@inheritDoc}. Also sets the ID for the embedded {@link TabInfo object}. + */ + @Override + public void setId( String id ) + { + super.setId( id ); + m_tabInfo.setId( id ); + } + /** * Sets the tab access key. * @@ -211,8 +265,7 @@ */ public void setAccesskey( String accessKey ) { - m_accesskey = TextUtil.replaceEntities( accessKey ); // take only the - // first char + m_tabInfo.setAccesskey( accessKey ); } /** @@ -222,7 +275,7 @@ */ public void setTitle( String title ) { - m_tabTitle = TextUtil.replaceEntities( title ); + m_tabInfo.setTitle( title ); } /** @@ -232,7 +285,7 @@ */ public void setTitleKey( String key ) { - m_tabTitleKey = TextUtil.replaceEntities( key ); + m_tabInfo.setTitleKey( key ); } /** @@ -242,21 +295,6 @@ */ public void setUrl( String url ) { - m_url = TextUtil.replaceEntities( url ); - } - - // insert ..accesskey.. in title - private boolean handleAccesskey() - { - if( (m_outputTitle == null) || (m_accesskey == null) ) - return false; - - int pos = m_outputTitle.toLowerCase().indexOf( m_accesskey.toLowerCase() ); - if( pos > -1 ) - { - m_outputTitle = m_outputTitle.substring( 0, pos ) + "" + m_outputTitle.charAt( pos ) - + "" + m_outputTitle.substring( pos + 1 ); - } - return true; + m_tabInfo.setUrl( url ); } } Modified: incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabbedSectionTag.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabbedSectionTag.java?rev=746883&r1=746882&r2=746883&view=diff ============================================================================== --- incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabbedSectionTag.java (original) +++ incubator/jspwiki/trunk/src/java/org/apache/wiki/tags/TabbedSectionTag.java Mon Feb 23 05:18:58 2009 @@ -20,121 +20,188 @@ */ package org.apache.wiki.tags; -import javax.servlet.jsp.*; -import javax.servlet.jsp.tagext.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspTagException; +import javax.servlet.jsp.JspWriter; +import javax.servlet.jsp.tagext.BodyContent; +import javax.servlet.jsp.tagext.BodyTagSupport; + +import org.apache.wiki.WikiEngine; +import org.apache.wiki.i18n.InternationalizationManager; +import org.apache.wiki.tags.TabTag.TabInfo; /** - * Generates tabbed page section: container for the Tab tag. - * Works together with the tabbedSection javacript. - * - *

Attributes

- *
    - *
  • defaultTab - Page name to refer to. Default is the current page. - *
- * - * @author Dirk Frederickx - * @since v2.3.63 + *

+ * Generates a container for page tabs, as defined by collaborating + * {@link TabTag} tags. Works together with the tabbedSection JavaScript. The + * output of the two collaborating tags is two sets of <div> + * elements. The first one will have a class of tabmenu, and + * includes the tab names, accessibility keys and and URL that contains the + * tab's contents (if specified). The second <div>, of + * class tabs, contains additional nested + * <div> elements that contain the actual tab content, if + * any was enclosed by the wiki:Tab tags. + *

+ *

+ * For example, consider the following tags as defined on a JSP: + *

+ *
+ * <wiki:TabbedSection defaultTab="pagecontent">
+ *   <wiki:Tab id="pagecontent" title="View" accesskey="V">
+ *     <p>This is the main tab.</p>
+ *   </wiki:Tab>
+ *   <wiki:Tab id="info" title="Info" accesskey="I" url="/PageInfo.jsp?page=Main" />
+ * </wiki:TabbedSection> + *
+ *

+ * This will cause the following HTML to be generated when the page contents are + * returned to the browser: + *

+ *
+ * <div class="tabmenu">
+ *   <a class="activetab" id="menu-pagecontent" accesskey="v" ><span class='accesskey'>V</span>iew</a>
+ *   <a id="menu-info" href='web-context/PageInfo.jsp?page=Main' accesskey="i" ><span class='accesskey'>I</span>nfo</a>
+ * </div>
+ * <div class="tabs">
+ *   <div id="pagecontent">
+ *     <p>This is the main tab.</p>
+ *   </div>
+ *   <div id="info" class="hidetab" />
+ *   <div style="clear:both;" ></div>
+ * </div> + *
+ *

Attributes

+ *
    + *
  • defaultTab - Page name to refer to. Default is the first tab.
  • + *
+ * + * @author Dirk Frederickx + * @author Andrew Jaquith + * @since v2.3.63 */ -// FIXME: Needs a bit more of explaining how this tag works. public class TabbedSectionTag extends BodyTagSupport { - private static final long serialVersionUID = 1702437933960026481L; - private String m_defaultTabId; - private String m_firstTabId; - private boolean m_defaultTabFound = false; + private static final long serialVersionUID = 2702437933960026481L; - private StringBuffer m_buffer = new StringBuffer(BUFFER_SIZE); - - private static final int FIND_DEFAULT_TAB = 0; - private static final int GENERATE_TABMENU = 1; - private static final int GENERATE_TABBODY = 2; - - private static final int BUFFER_SIZE = 1024; - - private int m_state = FIND_DEFAULT_TAB; + private WikiEngine m_engine; /** - * {@inheritDoc} + * Returns the TabCollection for the current HttpServletRequest. This + * method is always guaranteed to return a valid TabCollection. + * + * @param request the servlet request + * @return the TabCollection */ - @Override - public void release() + public static TabCollection getTabContext( ServletRequest request ) { - super.release(); - m_defaultTabId = m_firstTabId = null; - m_defaultTabFound = false; - m_buffer = new StringBuffer(); - m_state = FIND_DEFAULT_TAB; + TabCollection tc = (TabCollection) request.getAttribute( ATTR_TABS ); + if( tc == null ) + { + tc = new TabCollection(); + request.setAttribute( ATTR_TABS, tc ); + } + return tc; } + + private static final String ATTR_TABS = "JSPWiki.TabbedSection.Tags"; /** - * Set the id of the default tab (the tab which should be shown when - * the page is first loaded). - * - * @param anDefaultTabId ID attribute of the default tab. + * Holds the current set of related {@link TabbedSection} and {@link TabTag} + * tags. One TabCollection is created for each HTTPServletRequest, rather than + * per PageContext, because the tags could span multiple pages. */ - public void setDefaultTab(String anDefaultTabId) + public static class TabCollection { - m_defaultTabId = anDefaultTabId; - } + /** + * Private constructor to prevent direct instantiation. + */ + private TabCollection() + { + super(); + } - // FIXME: I don't really understand what this does - so Dirk, please - // add some documentation. - public boolean validateDefaultTab( String aTabId ) - { - if( m_firstTabId == null ) m_firstTabId = aTabId; - if( aTabId.equals( m_defaultTabId ) ) m_defaultTabFound = true; + private final List m_tabs = new ArrayList(); - return aTabId.equals( m_defaultTabId ); - } + /** + * Adds a child TabTag to the TabCollection. When the TabbedSection tag + * generates its menu and tab <div> elements, they will be + * generated in the order added. The tab added will be stored as a + * defensive copy, so that calls to + * {@link javax.servlet.jsp.tagext.Tag#release()} won't null out the + * cached copies. + * + * @param tab the tab to add + */ + public void addTab( TabTag tab ) throws JspTagException + { + if( tab == null ) + { + throw new JspTagException( "Cannot add null TabTag." ); + } - /** - * {@inheritDoc} - */ - @Override - public int doStartTag() throws JspTagException - { - return EVAL_BODY_BUFFERED; /* always look inside */ - } + TabInfo tabInfo = new TabInfo(); + tabInfo.setAccesskey( tab.getTabInfo().getAccesskey() ); + tabInfo.setId( tab.getTabInfo().getId() ); + tabInfo.setTitle( tab.getTabInfo().getTitle() ); + tabInfo.setTitleKey( tab.getTabInfo().getTitleKey() ); + tabInfo.setUrl( tab.getTabInfo().getUrl() ); + m_tabs.add( tabInfo ); + } + + /** + * Returns the list TabTag objects known to this TabCollection. + * + * @return the list of tab + */ + public List getTabs() + { + return m_tabs; + } + + /** + * Releases the TabCollection by clearing the internally cached list of + * TabTag objects. This method is called by + * {@link TabbedSectionTag#doEndTag()}. + */ + public void release() + { + m_tabs.clear(); + } - /** - * Returns true, if the tab system is currently trying to - * figure out which is the default tab. - * - * @return True, if finding the default tab. - */ - public boolean isStateFindDefaultTab() - { - return m_state == FIND_DEFAULT_TAB; } /** - * Returns true, if the tab system is currently generating - * the tab menu. - * - * @return True, if currently generating the menu itself. + * {@inheritDoc} */ - public boolean isStateGenerateTabMenu() + @Override + public void release() { - return m_state == GENERATE_TABMENU; + super.release(); + m_defaultTabID = null; } /** - * Returns true, if the tab system is currently generating - * the tab body. - * - * @return True, if the tab system is currently generating the tab body. + * {@inheritDoc} */ - public boolean isStateGenerateTabBody() + @Override + public int doStartTag() throws JspTagException { - return m_state == GENERATE_TABBODY; + m_engine = WikiEngine.getInstance( ((HttpServletRequest) pageContext.getRequest()).getSession().getServletContext(), null ); + return EVAL_BODY_BUFFERED; /* always look inside */ } - /** - * The tabbed section iterates 3 time through the underlying Tab tags - * - first it identifies the default tab (displayed by default) - * - second it generates the tabmenu markup (displays all tab-titles) - * - finally it generates the content of each tab. + * The tabbed section iterates 3 time through the underlying Tab tags - + * first it identifies the default tab (displayed by default) - second it + * generates the tabmenu markup (displays all tab-titles) - finally it + * generates the content of each tab. * * @return {@inheritDoc} * @throws {@inheritDoc} @@ -142,66 +209,152 @@ @Override public int doAfterBody() throws JspTagException { - if( isStateFindDefaultTab() ) - { - if( !m_defaultTabFound ) - { - m_defaultTabId = m_firstTabId; - } - m_state = GENERATE_TABMENU; - return EVAL_BODY_BUFFERED; - } - else if( isStateGenerateTabMenu() ) + // Stash the tag body (previously evaluated) + BodyContent body = getBodyContent(); + String bodyString = body.getString(); + + // Figure out the active (default) tab + TabCollection tc = getTabContext( pageContext.getRequest() ); + List tabs = tc.getTabs(); + + try { - if( bodyContent != null ) + // Generate menu divs; output to enclosing writer + body.clear(); + JspWriter writer = this.getPreviousOut(); + + writer.append( "
\n" ); + for( TabTag.TabInfo tab : tabs ) { - m_buffer.append( "
" ); - m_buffer.append( bodyContent.getString() ); - bodyContent.clearBody(); - m_buffer.append( "
\n" ); + // Is this the default tab? + if( tab.getId().equals( m_defaultTabID ) ) + { + m_defaultTabID = tab.getId(); + } + + // If default tag still not 't set, use the first one + if( m_defaultTabID == null || m_defaultTabID.length() == 0 ) + { + m_defaultTabID = tab.getId(); + } + + // Generate each menu item div + writeTabMenuItem( writer, tab ); } - m_state = GENERATE_TABBODY; - return EVAL_BODY_BUFFERED; + writer.append( "
\n" ); + + // Output the opening "tabs" div + writer.append( "
" ); + + // Remove the "hidden" class from the active tab + String activeTabDiv = "
"; + bodyString = bodyString.replace( activeTabDiv, "
" ); + + // Write back the stashed tag body + writer.append( bodyString ); + + // Append our closing div tags + writer.append( "
\n
\n" ); } - else if( isStateGenerateTabBody() ) + catch( IOException e ) { - if( bodyContent != null ) - { - m_buffer.append( "
" ); - m_buffer.append( bodyContent.getString() ); - bodyContent.clearBody(); - m_buffer.append( "
\n
\n" ); - } - return SKIP_BODY; + throw new JspTagException( e ); } + return SKIP_BODY; } + public int doEndTag() throws JspException + { + // Clear the TabCollection for the next caller + TabCollection tc = getTabContext( pageContext.getRequest() ); + tc.release(); + + return super.doEndTag(); + } + /** - * {@inheritDoc} + * Outputs a single menu item div element for a supplied tag. + * + * @param writer the JspWriter to write the output to + * @param tab the TabInfo object containing information about the tab + * @throws IOException */ - @Override - public int doEndTag() throws JspTagException + private void writeTabMenuItem( JspWriter writer, TabTag.TabInfo tab ) throws IOException { - try + writer.append( " 0 ) - { - getPreviousOut().write( m_buffer.toString() ); - } + writer.append( " class=\"activetab\"" ); } - catch(java.io.IOException e) + + // Generate the URL, if supplied + if( tab.getUrl() != null ) { - throw new JspTagException( "IO Error: " + e.getMessage() ); + writer.append( " href='" + tab.getUrl() + "'" ); } - //now reset some stuff for the next run -- ugh. - m_buffer = new StringBuffer(BUFFER_SIZE); - m_state = FIND_DEFAULT_TAB; - m_defaultTabId = null; - m_firstTabId = null; - m_defaultTabFound = false; - return EVAL_PAGE; + // Generate the tab title + String tabTitle = null; + if( tab.getTitleKey() != null ) + { + Locale locale = pageContext.getRequest().getLocale(); + InternationalizationManager i18n = m_engine.getInternationalizationManager(); + tabTitle = i18n.get( InternationalizationManager.TEMPLATES_BUNDLE, locale, tab.getTitleKey() ); + } + if( tabTitle == null ) + { + tabTitle = tab.getTitle(); + } + writer.append( ">" ); + + // Output the tab title + String accesskey = tab.getAccesskey(); + if( tabTitle != null ) + { + // Generate the access key, if supplied + if( accesskey != null ) + { + int pos = tabTitle.toLowerCase().indexOf( accesskey.toLowerCase() ); + if( pos > -1 ) + { + tabTitle = tabTitle.substring( 0, pos ) + "" + tabTitle.charAt( pos ) + "" + + tabTitle.substring( pos + 1 ); + } + } + writer.append( tabTitle ); + } + + // Output the closing tag + writer.append( "\n" ); + } + + private String m_defaultTabID = null; + + /** + * Returns the default tab ID. + * + * @return the tab ID + */ + protected String getDefaultTab() + { + return m_defaultTabID; + } + + /** + * Sets the id of the default tab. If not set, the first {@link TabTag} + * element encountered will be used as the default. + * + * @param defaultTab the id of tab to use as the default + */ + public void setDefaultTab( String defaultTab ) + { + m_defaultTabID = defaultTab; } }