You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2005/02/21 19:50:00 UTC

cvs commit: incubator-myfaces/webapps/examples/web tree2.jsp

matzew      2005/02/21 10:50:00

  Modified:    src/share/org/apache/myfaces/renderkit JSFAttr.java
               src/components/org/apache/myfaces/custom/tree2
                        HtmlTreeRenderer.java TreeTag.java
               tlds     myfaces_ext.tld
               webapps/examples/web tree2.jsp
  Log:
  Patch for the new tree component form Sean Schofield (now it supports JavaScript)
  
  Revision  Changes    Path
  1.10      +2 -2      incubator-myfaces/src/share/org/apache/myfaces/renderkit/JSFAttr.java
  
  Index: JSFAttr.java
  ===================================================================
  RCS file: /home/cvs/incubator-myfaces/src/share/org/apache/myfaces/renderkit/JSFAttr.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- JSFAttr.java	19 Feb 2005 09:03:01 -0000	1.9
  +++ JSFAttr.java	21 Feb 2005 18:49:59 -0000	1.10
  @@ -118,7 +118,7 @@
       // Tree attributes
       public static final String SHOW_NAV                    = "org.apache.myfaces.tree.SHOW_NAV";
       public static final String SHOW_LINES                  = "org.apache.myfaces.tree.SHOW_LINES";
  -
  +    public static final String CLIENT_SIDE_TOGGLE          = "org.apache.myfaces.tree.CLIENT_SIDE_TOGGLE";
   
       //~ Myfaces Extensions -------------------------------------------------------------------------------
   
  
  
  
  1.4       +194 -34   incubator-myfaces/src/components/org/apache/myfaces/custom/tree2/HtmlTreeRenderer.java
  
  Index: HtmlTreeRenderer.java
  ===================================================================
  RCS file: /home/cvs/incubator-myfaces/src/components/org/apache/myfaces/custom/tree2/HtmlTreeRenderer.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- HtmlTreeRenderer.java	19 Feb 2005 09:03:02 -0000	1.3
  +++ HtmlTreeRenderer.java	21 Feb 2005 18:49:59 -0000	1.4
  @@ -18,6 +18,7 @@
   
   
   import org.apache.myfaces.component.html.util.AddResource;
  +import org.apache.myfaces.renderkit.html.HtmlRendererUtils;
   import org.apache.myfaces.renderkit.html.HTML;
   import org.apache.myfaces.renderkit.JSFAttr;
   
  @@ -46,7 +47,9 @@
   public class HtmlTreeRenderer extends Renderer
   {
       private static final String NODE_LEVEL = "org.apache.myfaces.tree.NODE_LEVEL";
  +    private static final String JAVASCRIPT_ENCODED = "org.apache.myfaces.tree.JAVASCRIPT_ENCODED";
       private static final String NAV_COMMAND = "org.apache.myfaces.tree.NAV_COMMAND";
  +    private static final String TOGGLE_SPAN = "org.apache.myfaces.tree.TOGGLE_SPAN";
   
       private static final int NOTHING = 0;
       private static final int CHILDREN = 1;
  @@ -65,14 +68,15 @@
           super.decode(context, component);
   
           // see if one of the nav nodes was clicked, if so, then toggle appropriate node
  -        String nodeId = (String)context.getExternalContext().getRequestParameterMap().get(NAV_COMMAND);
  +        HtmlTree tree = (HtmlTree)component;
  +        String nodeId = (String)context.getExternalContext().getRequestParameterMap().get(tree.getId() +
  +            NamingContainer.SEPARATOR_CHAR + NAV_COMMAND);
   
           if (nodeId == null || nodeId.equals(""))
           {
               return;
           }
   
  -        HtmlTree tree = (HtmlTree) component;
           String originalNodeId = tree.getNodeId();
           tree.setNodeId(nodeId);
           tree.toggleExpanded();
  @@ -95,6 +99,9 @@
        */
       public void encodeChildren(FacesContext context, UIComponent component) throws IOException
       {
  +        // write javascript functions
  +        encodeJavascript(context, component);
  +
           // reset the nodeLevel (should already be zero but it can't hurt)
           component.getAttributes().put(NODE_LEVEL, new Integer(0));
   
  @@ -132,29 +139,47 @@
       private void encodeNodes(FacesContext context, ResponseWriter out, HtmlTree tree, String parentId, int childCount)
           throws IOException
       {
  -        // defaults are to show navigation icons and draw connecting lines
  +        String nodeId = (parentId != null) ? parentId + NamingContainer.SEPARATOR_CHAR + childCount : "0";
  +        String spanId = TOGGLE_SPAN + nodeId;
  +
  +        // defaults are to show navigation icons, draw connecting lines and provide client-side toggling of expand/collapse
           boolean showNav = true;
           boolean showLines = true;
  +        boolean clientSideToggle = true;
   
  -        // override showNav value with tag attribute (if applicable)
  -        Boolean booleanAttr = (Boolean)tree.getAttributes().get(JSFAttr.SHOW_NAV);
  +        // override showLines value with tag attribute (if applicable)
  +        Boolean booleanAttr = (Boolean)tree.getAttributes().get(JSFAttr.SHOW_LINES);
           if (booleanAttr != null)
           {
  -            showNav = booleanAttr.booleanValue();
  +            showLines = booleanAttr.booleanValue();
           }
   
  -        // override showLines value with tag attribute (if applicable)
  -        booleanAttr = (Boolean)tree.getAttributes().get(JSFAttr.SHOW_LINES);
  +        // override clientSideToggle value with tag attribute (if applicable)
  +        booleanAttr = (Boolean)tree.getAttributes().get(JSFAttr.CLIENT_SIDE_TOGGLE);
           if (booleanAttr != null)
           {
  -            showLines = booleanAttr.booleanValue();
  +            clientSideToggle = booleanAttr.booleanValue();
  +        }
  +
  +        // override showNav value with tag attribute (if applicable)
  +        booleanAttr = (Boolean)tree.getAttributes().get(JSFAttr.SHOW_NAV);
  +        if (booleanAttr != null)
  +        {
  +            showNav = booleanAttr.booleanValue();
  +        }
  +        if (clientSideToggle)
  +        {
  +            // we must show the nav icons if client side toggle is enabled (regardless of what user says)
  +            showNav = true;
           }
   
  -        tree.setNodeId(parentId != null ? parentId + NamingContainer.SEPARATOR_CHAR + childCount : "0");
  +
  +        tree.setNodeId(nodeId);
           TreeNode node = tree.getNode();
  -        UIComponent facet = tree.getFacet(node.getType());
  +        UIComponent nodeTypeFacet = tree.getFacet(node.getType());
  +        UIComponent nodeImgFacet = null;
   
  -        if (facet == null)
  +        if (nodeTypeFacet == null)
           {
               throw new IllegalArgumentException("Unable to locate facet with the name: " + node.getType());
           }
  @@ -162,11 +187,13 @@
           /** @todo - format rendered html */
   
           // start node table
  +        HtmlRendererUtils.writePrettyLineSeparator(context);
           out.startElement(HTML.TABLE_ELEM, tree);
           out.writeAttribute(HTML.CELLPADDING_ATTR, "0", null);
           out.writeAttribute(HTML.CELLSPACING_ATTR, "0", null);
           out.writeAttribute(HTML.BORDER_ATTR, "0", null);
           out.startElement(HTML.TR_ELEM, tree);
  +        HtmlRendererUtils.writePrettyLineSeparator(context);
   
           // render node padding
           String[] pathInfo = tree.getPathInformation(tree.getNodeId());
  @@ -193,6 +220,7 @@
           if (showNav)
           {
               String navSrc = null;
  +            String altSrc = null;
   
               int bitMask = NOTHING;
               bitMask += (node.getChildCount()>0) ? CHILDREN : NOTHING;
  @@ -220,30 +248,36 @@
   
                   case (CHILDREN + LAST):
                       navSrc = "images/nav-plus.gif";
  +                    altSrc = "images/nav-minus.gif";
                       break;
   
                   case (CHILDREN + LINES):
   
                       navSrc = "images/nav-plus-line-middle.gif";
  +                    altSrc = "images/nav-minus-line-middle.gif";
                       break;
   
                   case (CHILDREN + LINES + LAST):
   
                       navSrc = "images/nav-plus-line-last.gif";
  +                    altSrc = "images/nav-minus-line-last.gif";
                       break;
   
                   case (CHILDREN + EXPANDED):
   
                   case (CHILDREN + EXPANDED + LAST):
                       navSrc = "images/nav-minus.gif";
  +                    altSrc = "images/nav-plus.gif";
                       break;
   
                   case (CHILDREN + EXPANDED + LINES):
                       navSrc = "images/nav-minus-line-middle.gif";
  +                    altSrc = "images/nav-plus-line-middle.gif";
                       break;
   
                   case (CHILDREN + EXPANDED + LINES + LAST):
                       navSrc = "images/nav-minus-line-last.gif";
  +                    altSrc = "images/nav-plus-line-last.gif";
                       break;
   
                   default:
  @@ -263,33 +297,81 @@
                           null);
               }
   
  -            UICommand expandControl = tree.getExpandControl();
  -
  -            UIParameter param = new UIParameter();
  -            param.setName(NAV_COMMAND);
  -            param.setValue(tree.getNodeId());
  -
  +            // add the appropriate image for the nav control
               UIGraphic image = new UIGraphic();
               image.setUrl(navSrc);
               //image.setUrl(AddResource.getResourceMappedPath(HtmlTreeRenderer.class,navSrc, context));
  -
               Map imageAttrs = image.getAttributes();
               //imageAttrs.put(HTML.SRC_ATTR, AddResource.getResourceMappedPath(HtmlTreeRenderer.class, navSrc, context));
               imageAttrs.put(HTML.WIDTH_ATTR, "19");
               imageAttrs.put(HTML.HEIGHT_ATTR, "18");
               imageAttrs.put(HTML.BORDER_ATTR, "0");
   
  -            // remove whatever children (if any) this control had previously and add the appropriate image
  -            expandControl.getChildren().clear();
  -            expandControl.getChildren().add(param);
  -            expandControl.getChildren().add(image);
  -
  -            tree.getChildren().add(expandControl);
  -
  -            expandControl.encodeBegin(context);
  -            expandControl.encodeChildren(context);
  -            expandControl.encodeEnd(context);
  -
  +            if (clientSideToggle)
  +            {
  +                /**
  +                 * With client side toggle, user has the option to specify open/closed images for the node (in addition to
  +                 * the navigtion ones provided by the component.)
  +                 */
  +                String expandImgSrc = "";
  +                String collapseImgSrc = "";
  +                String nodeImageId = "";
  +
  +                UIComponent expandFacet = nodeTypeFacet.getFacet("expand");
  +                if (expandFacet != null)
  +                {
  +                    UIGraphic expandImg = (UIGraphic)expandFacet;
  +                    expandImgSrc = expandImg.getUrl();
  +                    if (expandImg.isRendered())
  +                    {
  +                        expandImg.setId(null);
  +                        nodeImageId = expandImg.getClientId(context);
  +                        nodeImgFacet = expandFacet;
  +                    }
  +                }
  +
  +                UIComponent collapseFacet = nodeTypeFacet.getFacet("collapse");
  +                if (collapseFacet != null)
  +                {
  +                    UIGraphic collapseImg = (UIGraphic)collapseFacet;
  +                    collapseImgSrc = collapseImg.getUrl();
  +                    if (collapseImg.isRendered())
  +                    {
  +                        collapseImg.setId(null);
  +                        nodeImageId = collapseImg.getClientId(context);
  +                        nodeImgFacet = collapseFacet;
  +                    }
  +                }
  +
  +                if (node.getChildCount() > 0)
  +                {
  +                    imageAttrs.put(HTML.ONCLICK_ATTR, "treeNavClick('" + spanId + "', '" + image.getClientId(context) + "', '" +
  +                                   navSrc + "', '" + altSrc + "', '" + nodeImageId + "', '" + expandImgSrc + "', '" +
  +                                   collapseImgSrc + "');");
  +
  +                    imageAttrs.put(HTML.STYLE_ATTR, "cursor:hand;cursor:pointer");
  +                }
  +                image.encodeBegin(context);
  +                image.encodeEnd(context);
  +            }
  +            else
  +            {
  +                // set up the expand control and remove whatever children (if any) this control had previously
  +                UICommand expandControl = tree.getExpandControl();
  +                expandControl.getChildren().clear();
  +
  +                UIParameter param = new UIParameter();
  +                param.setName(tree.getId() + NamingContainer.SEPARATOR_CHAR + NAV_COMMAND);
  +                param.setValue(tree.getNodeId());
  +                expandControl.getChildren().add(param);
  +                expandControl.getChildren().add(image);
  +
  +                tree.getChildren().add(expandControl);
  +
  +                expandControl.encodeBegin(context);
  +                expandControl.encodeChildren(context);
  +                expandControl.encodeEnd(context);
  +            }
               //out.startElement(HTML.IMG_ELEM, tree);
               //out.writeURIAttribute(HTML.SRC_ATTR, AddResource.getResourceMappedPath(HtmlTreeRenderer.class, navSrc, context) , null);
               //out.writeAttribute(HTML.WIDTH_ATTR, "19", null);
  @@ -301,15 +383,20 @@
   
           // render node
           out.startElement(HTML.TD_ELEM, tree);
  -        encodeRecursive(context, facet);
  +        if (nodeImgFacet != null)
  +        {
  +            encodeRecursive(context, nodeImgFacet);
  +        }
  +        encodeRecursive(context, nodeTypeFacet);
           out.endElement(HTML.TD_ELEM);
   
           // end node table
           out.endElement(HTML.TR_ELEM);
           out.endElement(HTML.TABLE_ELEM);
  +        HtmlRendererUtils.writePrettyLineSeparator(context);
   
  -        // only encode the children if this node is expanded
  -        if (tree.isNodeExpanded())
  +        // only encode the children if clientSideToggle is true or if this node is expanded (regardless of clientSideToggle)
  +        if (clientSideToggle == true || tree.isNodeExpanded())
           {
               int nodeLevel = ((Integer)tree.getAttributes().get(NODE_LEVEL)).intValue();
               nodeLevel++;
  @@ -319,11 +406,32 @@
               String currId = tree.getNodeId();
               List children = node.getChildren();
   
  +            // if client side toggling is on, add a span to be used for displaying/hiding children
  +            if (clientSideToggle)
  +            {
  +                out.startElement(HTML.SPAN_ELEM, tree);
  +                out.writeAttribute(HTML.ID_ATTR, spanId, null);
  +
  +                if (tree.isNodeExpanded())
  +                {
  +                    out.writeAttribute(HTML.STYLE_ATTR, "display:block", null);
  +                }
  +                else
  +                {
  +                    out.writeAttribute(HTML.STYLE_ATTR, "display:none", null);
  +                }
  +            }
  +
               for (int i = 0; i < children.size(); i++)
               {
                   encodeNodes(context, out, tree, currId, kidId++);
               }
   
  +            if (clientSideToggle)
  +            {
  +                out.endElement(HTML.SPAN_ELEM);
  +            }
  +
               nodeLevel = ((Integer)tree.getAttributes().get(NODE_LEVEL)).intValue();
               nodeLevel--;
               tree.getAttributes().put(NODE_LEVEL, new Integer(nodeLevel));
  @@ -354,4 +462,56 @@
   
           component.encodeEnd(context);
       }
  +
  +    /**
  +     * Encodes any stand-alone javascript functions that are needed.
  +     *
  +     * @param context FacesContext
  +     * @param component UIComponent
  +     * @throws IOException
  +     */
  +    private void encodeJavascript(FacesContext context, UIComponent component) throws IOException
  +    {
  +        // check to see if javascript has already been written (which could happen if more than one tree on the same page)
  +        if (context.getExternalContext().getRequestMap().containsKey(JAVASCRIPT_ENCODED))
  +        {
  +            return;
  +        }
  +
  +        ResponseWriter out = context.getResponseWriter();
  +
  +        out.startElement(HTML.SCRIPT_ELEM, component);
  +        out.writeAttribute(HTML.SCRIPT_LANGUAGE_ATTR, "javascript", null);
  +        HtmlRendererUtils.writePrettyLineSeparator(context);
  +
  +        // render javascript function for client-side toggle (it won't be used if user has opted for server-side toggle)
  +        out.writeText("function treeNavClick(spanId, navImageId, image1, image2, nodeImgId, expandImg, collapseImg) {", null);
  +        out.writeText("var navSpan = document.getElementById(spanId);", null);
  +        out.writeText("var displayStyle = navSpan.style.display;", null);
  +        out.writeText("if (displayStyle == 'none') { displayStyle = 'block' } else { displayStyle = 'none'; }", null);
  +        out.writeText("navSpan.style.display = displayStyle;", null);
  +        out.writeText("var navImage = document.getElementById(navImageId);", null);
  +        out.writeText("if (navImage.src.indexOf(image1)>=0) navImage.src = image2; else navImage.src = image1;", null);
  +        out.writeText("if (nodeImgId != '') {", null);
  +        out.writeText("var nodeImg = document.getElementById(nodeImgId);", null);
  +        out.writeText("if (nodeImg.src.indexOf(expandImg) >=0) nodeImg.src = collapseImg; else nodeImg.src = expandImg;}", null);
  +        //out.writeText("foo();", null);
  +        //out.writeText("setCookie('FOO', spanId, null, null, null, null);", null);
  +        out.writeText("}", null);
  +
  +        // render the javascript containing cookie manipulation functions
  +        /** @todo consider moving functionality outside component so it can be reusued */
  +//        out.writeText("function setCookie(name, value, expires, path, domain, secure) {", null);
  +//        out.writeText("var curCookie = name + '=' + escape(value) + ((expires) ? '; expires=' + expires.toGMTString() : ''", null);
  +//        out.writeText(" + (path) ? '; path=' + path : '') + ((domain) ? '; domain=' + domain : '') + ", null);
  +//        out.writeText("((secure) ? '; secure' : '');document.cookie = curCookie;}", null);
  +
  +//        out.writeText("function foo() { alert('stuff');", null);
  +//        out.writeText("document.cookie = 'ppkcookie1=testcookie; expires=Thu, 2 Aug 2005 20:47:11 UTC; path=/';", null);
  +//        out.writeText("}", null);
  +
  +        out.endElement(HTML.SCRIPT_ELEM);
  +
  +        context.getExternalContext().getRequestMap().put(JAVASCRIPT_ENCODED, Boolean.TRUE);
  +    }
   }
  \ No newline at end of file
  
  
  
  1.5       +9 -1      incubator-myfaces/src/components/org/apache/myfaces/custom/tree2/TreeTag.java
  
  Index: TreeTag.java
  ===================================================================
  RCS file: /home/cvs/incubator-myfaces/src/components/org/apache/myfaces/custom/tree2/TreeTag.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- TreeTag.java	19 Feb 2005 09:03:02 -0000	1.4
  +++ TreeTag.java	21 Feb 2005 18:49:59 -0000	1.5
  @@ -35,6 +35,7 @@
       private String _varNodeToggler;
       private String _showLines;
       private String _showNav;
  +    private String _clientSideToggle;
   
       public void release()
       {
  @@ -45,6 +46,7 @@
           _varNodeToggler=null;
           _showLines = null;
           _showNav = null;
  +        _clientSideToggle = null;
       }
   
       public String getComponentType()
  @@ -85,6 +87,11 @@
           _showNav = showNav;
       }
   
  +    public void setClientSideToggle(String clientSideToggle)
  +    {
  +        _clientSideToggle = clientSideToggle;
  +    }
  +
       protected void setProperties(UIComponent component)
       {
           super.setProperties(component);
  @@ -109,5 +116,6 @@
   
           setBooleanProperty(component, JSFAttr.SHOW_NAV, _showNav);
           setBooleanProperty(component, JSFAttr.SHOW_LINES, _showLines);
  +        setBooleanProperty(component, JSFAttr.CLIENT_SIDE_TOGGLE, _clientSideToggle);
       }
   }
  \ No newline at end of file
  
  
  
  1.170     +11 -3     incubator-myfaces/tlds/myfaces_ext.tld
  
  Index: myfaces_ext.tld
  ===================================================================
  RCS file: /home/cvs/incubator-myfaces/tlds/myfaces_ext.tld,v
  retrieving revision 1.169
  retrieving revision 1.170
  diff -u -r1.169 -r1.170
  --- myfaces_ext.tld	19 Feb 2005 09:03:02 -0000	1.169
  +++ myfaces_ext.tld	21 Feb 2005 18:49:59 -0000	1.170
  @@ -1742,15 +1742,23 @@
               <name>showNav</name>
               <required>false</required>
               <rtexprvalue>false</rtexprvalue>
  -            <description>Show the "plus" and "minus" navigation icons (default is true)</description>
  +            <description>
  +                Show the "plus" and "minus" navigation icons (default is true.) Value is ignored if
  +                clientSideToggle is true.
  +            </description>
           </attribute>
           <attribute>
               <name>showLines</name>
               <required>false</required>
               <rtexprvalue>false</rtexprvalue>
  -            <description>Show the connecting lines (default is true)</description>
  +            <description>Show the connecting lines (default is true.)</description>
  +        </attribute>
  +        <attribute>
  +            <name>clientSideToggle</name>
  +            <required>false</required>
  +            <rtexprvalue>false</rtexprvalue>
  +            <description>Perform client-side toggling of expand/collapse state via javascript (default is true.)</description>
           </attribute>
  -
       </tag>
   
       <!-- panelStack -->
  
  
  
  1.2       +79 -11    incubator-myfaces/webapps/examples/web/tree2.jsp
  
  Index: tree2.jsp
  ===================================================================
  RCS file: /home/cvs/incubator-myfaces/webapps/examples/web/tree2.jsp,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- tree2.jsp	15 Feb 2005 22:23:17 -0000	1.1
  +++ tree2.jsp	21 Feb 2005 18:50:00 -0000	1.2
  @@ -5,13 +5,13 @@
   <!--
   /*
    * Copyright 2005 The Apache Software Foundation.
  - * 
  + *
    * 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.
  @@ -28,13 +28,13 @@
   <!--
   /*
    * Copyright 2004 The Apache Software Foundation.
  - * 
  + *
    * 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.
  @@ -73,16 +73,84 @@
           <f:facet name="body">
               <h:panelGroup id="body">
   
  +              <!-- Expand/Collapse Handled By Client -->
  +
  +              <%--
  +              NOTE: There is no commandLink for the folders because the toggling of expand/collapse is handled on the client
  +              via javascript.  We have a command link for document but that is really application specific.  In a real application
  +              you would likely specify an action method/listener and do something interesting with the node identifier that is
  +              submitted.
  +
  +              First child in the expand/collapse facet should be image (if any)
  +              --%>
  +                <f:verbatim>
  +                    <b>Client-Side Tree</b>
  +                    <br/>
  +                </f:verbatim>
  +
                 <x:tree2 value="#{treeBacker.treeData}" var="node" varNodeToggler="t">
                   <f:facet name="person">
                     <h:panelGroup>
  +                    <f:facet name="expand">
  +                      <h:graphicImage value="images/yellow-folder-open.png" rendered="#{t.nodeExpanded}" border="0"/>
  +                    </f:facet>
  +                    <f:facet name="collapse">
  +                      <h:graphicImage value="images/yellow-folder-closed.png" rendered="#{!t.nodeExpanded}" border="0"/>
  +                    </f:facet>
  +                    <h:outputText value="#{node.description}" styleClass="nodeFolder"/>
  +                  </h:panelGroup>
  +                </f:facet>
  +                <f:facet name="foo-folder">
  +                  <h:panelGroup>
  +                    <f:facet name="expand">
  +                      <h:graphicImage value="images/yellow-folder-open.png" rendered="#{t.nodeExpanded}" border="0"/>
  +                    </f:facet>
  +                    <f:facet name="collapse">
  +                      <h:graphicImage value="images/yellow-folder-closed.png" rendered="#{!t.nodeExpanded}" border="0"/>
  +                    </f:facet>
  +                    <h:outputText value="#{node.description}" styleClass="nodeFolder"/>
  +                    <h:outputText value=" (#{node.childCount})" styleClass="childCount" rendered="#{!empty node.children}"/>
  +                  </h:panelGroup>
  +                </f:facet>
  +                <f:facet name="bar-folder">
  +                  <h:panelGroup>
  +                    <f:facet name="expand">
  +                      <h:graphicImage value="images/blue-folder-open.png" rendered="#{t.nodeExpanded}" border="0"/>
  +                    </f:facet>
  +                    <f:facet name="collapse">
  +                      <h:graphicImage value="images/blue-folder-closed.png" rendered="#{!t.nodeExpanded}" border="0"/>
  +                    </f:facet>
  +                    <h:outputText value="#{node.description}" styleClass="nodeFolder"/>
  +                    <h:outputText value=" (#{node.childCount})" styleClass="childCount" rendered="#{!empty node.children}"/>
  +                  </h:panelGroup>
  +                </f:facet>
  +                <f:facet name="document">
  +                  <h:panelGroup>
  +                    <h:commandLink immediate="true" styleClass="document">
  +                      <h:graphicImage value="images/document.png" border="0"/>
  +                      <h:outputText value="#{node.description}"/>
  +                      <f:param name="docNum" value="#{node.identifier}"/>
  +                    </h:commandLink>
  +                  </h:panelGroup>
  +                </f:facet>
  +              </x:tree2>
  +
  +                <f:verbatim>
  +                    <b>Server-Side Tree</b>
  +                    <br/>
  +                </f:verbatim>
  +
  +              <!-- Expand/Collapse Handled By Server -->
  +              <x:tree2 value="#{treeBacker.treeData}" var="node" varNodeToggler="t" clientSideToggle="false">
  +                <f:facet name="person">
  +                  <h:panelGroup>
                       <h:commandLink immediate="true" action="#{t.toggleExpanded}">
                         <h:graphicImage value="/images/yellow-folder-open.png" rendered="#{t.nodeExpanded}" border="0"/>
                         <h:graphicImage value="/images/yellow-folder-closed.png" rendered="#{!t.nodeExpanded}" border="0"/>
                       </h:commandLink>
                       <h:outputText value="#{node.description}" styleClass="nodeFolder"/>
                     </h:panelGroup>
  -                </f:facet>      
  +                </f:facet>
                   <f:facet name="foo-folder">
                     <h:panelGroup>
                       <h:commandLink immediate="true" action="#{t.toggleExpanded}">
  @@ -102,19 +170,19 @@
                       <h:outputText value="#{node.description}" styleClass="nodeFolder"/>
                       <h:outputText value=" (#{node.childCount})" styleClass="childCount" rendered="#{!empty node.children}"/>
                     </h:panelGroup>
  -                </f:facet>        
  +                </f:facet>
                   <f:facet name="document">
                     <h:panelGroup>
                       <h:commandLink immediate="true" styleClass="document">
                         <h:graphicImage value="/images/document.png" border="0"/>
                         <h:outputText value="#{node.description}"/>
  -                      <f:param name="userId" value="#{node.identifier}"/>
  +                      <f:param name="docNum" value="#{node.identifier}"/>
                       </h:commandLink>
                     </h:panelGroup>
                   </f:facet>
                 </x:tree2>
  -      
  -                <f:verbatim><br></f:verbatim>
  +
  +                <f:verbatim><br/></f:verbatim>
   
               </h:panelGroup>
           </f:facet>