You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by cr...@apache.org on 2005/07/16 06:37:50 UTC

svn commit: r219287 - in /struts/shale/trunk: ./ clay-plugin/src/conf/ clay-plugin/src/java/org/apache/shale/clay/component/ clay-plugin/src/java/org/apache/shale/clay/component/chain/ clay-plugin/src/java/org/apache/shale/clay/faces/ clay-plugin/src/j...

Author: craigmcc
Date: Fri Jul 15 21:37:46 2005
New Revision: 219287

URL: http://svn.apache.org/viewcvs?rev=219287&view=rev
Log:
Commit the changes for the full HTML templating update to the Clay plugin,
including an update to the use cases example.

PR:  Bugzilla #35762
Submitted By:  Gary VanMatre <gvanmatre AT comcast.net>

Added:
    struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/faces/
    struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/faces/ClayViewHandler.java
    struts/shale/trunk/use-cases/src/web/rolodex/hrolodex.html
Modified:
    struts/shale/trunk/build.xml
    struts/shale/trunk/clay-plugin/src/conf/faces-config.xml
    struts/shale/trunk/clay-plugin/src/conf/view-config.xml
    struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/Clay.java
    struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java
    struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java
    struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommandButtonBuilder.java
    struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java
    struts/shale/trunk/default.properties
    struts/shale/trunk/use-cases/src/java/org/apache/shale/usecases/view/Bundle.properties
    struts/shale/trunk/use-cases/src/web/WEB-INF/clay-config.xml
    struts/shale/trunk/use-cases/src/web/WEB-INF/faces-config.xml
    struts/shale/trunk/use-cases/src/web/WEB-INF/web.xml
    struts/shale/trunk/use-cases/src/web/usecases.jsp

Modified: struts/shale/trunk/build.xml
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/build.xml?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/build.xml (original)
+++ struts/shale/trunk/build.xml Fri Jul 15 21:37:46 2005
@@ -17,7 +17,7 @@
 -->
 
 
-<project name="Shale Framework Global Build" basedir=".">
+<project name="global" basedir=".">
 
 
   <!-- ===================== Initialize Property Values ==================== -->
@@ -217,9 +217,93 @@
   </path>
 
 
-  <!-- ====================== Download Dependencies ======================== -->
+  <!-- ====================== Common Class Path References ================= -->
 
 
+  <!-- External dependencies *without* a JSF implementation -->
+  <path            id="external.path">
+    <path       refid="commons-beanutils.path"/>
+    <path       refid="commons-chain.path"/>
+    <path       refid="commons-digester.path"/>
+    <path       refid="commons-logging.path"/>
+    <path       refid="commons-validator.path"/>
+    <path       refid="jsp-api.path"/>
+    <path       refid="jstl-ri-api.path"/>
+    <path       refid="portlet-api.path"/>
+    <path       refid="servlet-api.path"/>
+    <path       refid="spring-beans.path"/>
+    <path       refid="spring-context.path"/>
+    <path       refid="spring-core.path"/>
+    <path       refid="spring-web.path"/>
+    <path       refid="tiles.path"/>
+  </path>
+
+
+  <!-- External dependencies plus JSF RI -->
+  <path            id="external-jsfri.path">
+    <path       refid="external.path"/>
+    <path       refid="jsf-ri-api.path"/>
+  </path>
+
+
+  <!-- External dependencies plus MyFaces -->
+  <path            id="external-myfaces.path">
+    <path       refid="external.path"/>
+    <path       refid="myfaces-api.path"/>
+  </path>
+
+
+  <!-- External plus test dependencies *without* a JSF implementation -->
+  <path            id="test.path">
+    <path       refid="external.path"/>
+    <path       refid="junit.path"/>
+    <path       refid="shale-test.path"/>
+  </path>
+
+
+  <!-- External plus test dependencies plus JSF RI -->
+  <path            id="test-jsfri.path">
+    <path       refid="test.path"/>
+    <path       refid="jsf-ri-api.path"/>
+  </path>
+
+
+  <!-- External plus test dependencies plus MyFaces -->
+  <path            id="test-myfaces.path">
+    <path       refid="test.path"/>
+    <path       refid="myfaces-api.path"/>
+  </path>
+
+
+  <!-- ======================== Pass Through Targets ======================= -->
+
+
+  <!-- These targets execute the corresponding target for all modules. -->
+
+
+  <target        name="clean"
+          description="Execute 'clean' all all modules">
+
+    <antcall   target="execute">
+      <param     name="target"
+                value="clean"/>
+    </antcall>
+
+  </target>
+
+
+
+  <!-- =================== Initialize Local Repository ===================== -->
+
+
+  <!-- These targets are used to load all dependencies into the local repository
+       (by default, the "lib" directory.  Generally, they should be executed
+       once when the source configuration is initially configured, but they
+       may be repeated to ensure that the loaded dependencies are current. -->
+
+
+  <!-- Download freely available dependencies from the ${maven.repo}
+       Maven repository into directory ${lib.dir}. -->
   <target        name="download-dependencies"
           description="Download freely available dependencies">
 
@@ -366,9 +450,8 @@
   </target>
 
 
-  <!-- ======= Copy JavaServer Faces Reference Implementation ============== -->
-
-
+  <!-- Copy relevant artifacts from the JavaServer Faces reference
+       implementation installed at ${jsfri.dir} to ${lib.dir}.  -->
   <target        name="copy-jsf-ri"
           description="Copy artifacts from JSF Reference Implementation">
 
@@ -381,9 +464,8 @@
   </target>
 
 
-  <!-- ============= Copy Standalone Tiles ================================= -->
-
-
+  <!-- Copy relevant artifacts from the compiled standalone Tiles implementation
+       (currently in the Struts sandbox) from ${tiles.dir} into ${lib.dir}.  -->
   <target        name="copy-tiles"
           description="Copy standalone Tiles artifacts">
 
@@ -392,5 +474,36 @@
                  file="${tiles.dir}/lib/tiles-core.jar"/>
 
   </target>
+
+
+  <!-- ==================== Internal Targets =============================== -->
+
+
+
+  <!-- These targets are not intended for direct use.  They are used internally
+       by other targets. -->
+
+
+  <!-- Recursively execute ${target} across all modules -->
+  <target        name="execute">
+
+    <echo     message="Executing ${target} on module core-library"/>
+    <ant          dir="${root.dir}/core-library"
+               target="${target}"/>
+
+    <echo     message="Executing ${target} on module clay-plugin"/>
+    <ant          dir="${root.dir}/clay-plugin"
+               target="${target}"/>
+
+    <echo     message="Executing ${target} on module test-framework"/>
+    <ant          dir="${root.dir}/test-framework"
+               target="${target}"/>
+
+    <echo     message="Executing ${target} on module use-cases"/>
+    <ant          dir="${root.dir}/use-cases"
+               target="${target}"/>
+
+  </target>
+
 
 </project>

Modified: struts/shale/trunk/clay-plugin/src/conf/faces-config.xml
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/conf/faces-config.xml?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/clay-plugin/src/conf/faces-config.xml (original)
+++ struts/shale/trunk/clay-plugin/src/conf/faces-config.xml Fri Jul 15 21:37:46 2005
@@ -32,6 +32,12 @@
 
 <faces-config>
 
+  <application>
+    <view-handler>
+       org.apache.shale.clay.faces.ClayViewHandler
+    </view-handler>
+  </application>
+
   <component>
     <description>
       The "Clay" component dynamically composes a tree of child components

Modified: struts/shale/trunk/clay-plugin/src/conf/view-config.xml
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/conf/view-config.xml?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/clay-plugin/src/conf/view-config.xml (original)
+++ struts/shale/trunk/clay-plugin/src/conf/view-config.xml Fri Jul 15 21:37:46 2005
@@ -205,4 +205,15 @@
       </attributes>	
   </component>
 
+
+  <!-- Nested Clay Component -->    
+  <component jsfid="clay" componentType="org.apache.shale.clay.component.Clay" 
+       allowBody="false">
+    <attributes>
+      <set name="jsfid" value="RUNTIME"/>
+      <set name="managedBeanName" useValueLateBinding="false"/>
+      <set name="shapeValidator" useMethodLateBinding="true"/> 
+    </attributes>
+  </component>	
+
 </view>

Modified: struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/Clay.java
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/Clay.java?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/Clay.java (original)
+++ struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/Clay.java Fri Jul 15 21:37:46 2005
@@ -315,7 +315,7 @@
             try {
                 catalog = getCatalog();
             } catch (Exception e) {
-                System.out.println(e);
+                log.error(e);
             }
             Command command = catalog
                     .getCommand(Globals.ADD_COMPONENT_COMMAND_NAME);
@@ -331,7 +331,6 @@
             
         }
         
-        super.encodeBegin(context);
     }
     
     /**
@@ -342,7 +341,7 @@
     protected void recursiveRenderChildren(UIComponent child,
             FacesContext context) throws IOException {
         
-        if (!child.getRendersChildren()) {
+        if (!child.getRendersChildren() || child == this) {
             Iterator ci = child.getChildren().iterator();
             while (ci.hasNext()) {
                 UIComponent c = (UIComponent) ci.next();
@@ -368,11 +367,12 @@
      * </p>
      */
     public void encodeChildren(FacesContext context) throws IOException {
-        super.encodeChildren(context);
         
         if (log.isTraceEnabled())
             log.trace("encodeChildren(FacesContext)");
-        
+
+        recursiveRenderChildren(this, context);
+
     }
     
     /**
@@ -386,11 +386,6 @@
         if (log.isTraceEnabled())
             log.trace("encodeEnd(FacesContext)");
         
-        // if the parents, parent handles the renderering, like a pannelGrid, it
-        // will take care of the rendering of the root subview node.
-        if (!getParent().getRendersChildren()) {
-            recursiveRenderChildren(this, context);
-        }
     }
     
     /**
@@ -452,5 +447,17 @@
         
         return aobj;
     }
+
+    /**
+     * <p>Returns <code>true</code> indicating that this
+     * component will render it's children.  This will 
+     * indicate to a parent component that renders children 
+     * not to recursively render Clay's children -
+     * simply invoke encodeChildren(FacesContext).</p>
+     */
+    public boolean getRendersChildren() {
+       return true;
+    }
+
     
 }

Modified: struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java (original)
+++ struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/component/chain/PropertyValueCommand.java Fri Jul 15 21:37:46 2005
@@ -75,9 +75,21 @@
         FacesContext facesContext = clayContext.getFacesContext();
         if (facesContext == null)
             throw new NullPointerException(messages.getMessage("clay.null.facesContext"));
-        if (attributeBean.getValue() != null
-                && (attributeBean.getValue().indexOf('{') > -1 && attributeBean
-                .getValue().indexOf('}') > -1)) {
+        
+        //when using the html templating, javascript and css will have matching curly braces {}.
+        //and pound sign # too.  
+        int pound = -1;
+        int leftCurly = -1;
+        int rightCurly = -1;
+        
+        if (attributeBean.getValue() != null) {
+            pound = attributeBean.getValue().indexOf('#');
+            leftCurly = attributeBean.getValue().indexOf('{');
+            rightCurly = attributeBean.getValue().indexOf('}');            
+        }
+        if ((pound > -1 && leftCurly > -1 && rightCurly > -1) 
+                && (rightCurly > leftCurly) && ((leftCurly - pound) == 1)) {
+            
             String expr = replaceMnemonic(clayContext);
             ValueBinding binding = facesContext.getApplication()
                                                    .createValueBinding(expr);
@@ -90,7 +102,9 @@
                 // Should pass a method value binding expressions to the components 
                 // that use non-standard names like the clay component's shapValidator 
                 // method binding expression.  Standard method binding properties will
-                // be handled by the other property commands
+                // be handled by the other property commands (PropertyActionCommand,
+                // PropertyActionListenerCommand, PropertyValidatorCommand, and
+                // PropertyValueChangeListenerCommand)
 
                 ((UIComponent) child).getAttributes().put(attributeBean.getName(), expr);       
                    
@@ -100,15 +114,11 @@
                     PropUtils.setProperty(child, attributeBean.getName(), value);
                 } catch (Exception e) {
                     
-                    // catch the exception and check to see if the attribute name is in the 
-                    // components attributes Map.  If it is, set the value as a string.  
-                    if (((UIComponent) child).getAttributes().containsKey(attributeBean.getName())) {
-                        ((UIComponent) child).getAttributes().put(attributeBean.getName(), expr);       
-                    } else {
-                        // not a valid attribute, throw the exception
-                        log.error(e);
-                        throw e;
-                    }
+                    // Catch the exception logging it.  Assume that the value is for
+                    // an attribute that has no corresponding component property. 
+                    // After all, clay can be shaped into anything - it's all good.
+                    log.error(e);
+                    ((UIComponent) child).getAttributes().put(attributeBean.getName(), expr);       
                 }
                 
             }

Added: struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/faces/ClayViewHandler.java
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/faces/ClayViewHandler.java?rev=219287&view=auto
==============================================================================
--- struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/faces/ClayViewHandler.java (added)
+++ struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/faces/ClayViewHandler.java Fri Jul 15 21:37:46 2005
@@ -0,0 +1,295 @@
+/*
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Id$
+ */
+package org.apache.shale.clay.faces;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Locale;
+
+import javax.faces.FacesException;
+import javax.faces.application.StateManager;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.servlet.ServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.shale.ViewController;
+import org.apache.shale.ViewControllerMapper;
+import org.apache.shale.clay.component.Clay;
+import org.apache.shale.clay.config.Globals;
+import org.apache.shale.faces.ShaleConstants;
+import org.apache.shale.view.DefaultViewControllerMapper;
+
+/**
+ * <p>This <code>ViewHandler</code> will handle full HTML template views using the 
+ * {@link Clay} component as the single subtree under the view root.  Views will 
+ * be intercepted having a suffix matching the registered clay template suffix 
+ * in the web deployment descriptor.  The default suffix is ".clay".  All other 
+ * view render requests that don't match the suffix will be delegated to the 
+ * original decorated view handler.</p>
+ */
+public class ClayViewHandler extends ViewHandler {
+
+    /**
+     * <p>
+     * Commons logger utility class instance
+     * </p>
+     */
+    private static Log log;
+    static {
+        log = LogFactory.getLog(ClayViewHandler.class);
+    }
+        
+    /**
+     * <p>The decorated view handler.</p>
+     */
+    private ViewHandler original = null;
+    
+    /**
+     * <p>The {@link Clay} component <code>id</code> property value.</p>
+     */
+    private static final String CLAY_VIEW_ID = "clayView";
+    
+    /**
+     * <p>{@link Clay} <code>componentType</code> that is used to create a instance using
+     * the faces Application object.</p>
+     */
+    private static final String CLAY_COMPONENT_TYPE = "org.apache.shale.clay.component.Clay";
+
+    /**
+     * <p>Holds the suffix used to identify a Clay HTML full view template.</p>
+     */
+    private String suffix = null;
+
+    /**
+     * <p>Cached {@link ViewControllerMapper} we will use to translate
+     * view identifiers to the class name of a {@link ViewController}.
+     * This code is borrowed from {@link ShaleViewController}.</p>
+     */
+    private ViewControllerMapper mapper = null;
+
+    
+    // Specified by ViewHandler
+    public ClayViewHandler(ViewHandler original) {
+        this.original = original;
+        
+        if (log.isInfoEnabled())
+           log.info("Loading Clay View Handler");
+    }
+
+    // Specified by ViewHandler
+    public Locale calculateLocale(FacesContext context) {
+        return original.calculateLocale(context);
+    }
+
+    // Specified by ViewHandler
+    public String calculateRenderKitId(FacesContext context) {
+        return original.calculateRenderKitId(context);
+    }
+
+    // Specified by ViewHandler
+    public UIViewRoot createView(FacesContext context, String viewId) {
+        return original.createView(context, viewId);
+    }
+
+    /**
+     * <p>If the <code>viewId</code> is suffixed with the Clay template suffix,
+     * rewrite the returned actionUrl with a clay suffix.  The super implementation
+     * will assume ".jsp" or whatever the <code>javax.faces.DEFAULT_SUFFIX</code> is 
+     * set to in the web deployment descriptor.</p>
+     */
+    public String getActionURL(FacesContext context, String viewId) {
+        StringBuffer actionUrl = new StringBuffer(original.getActionURL(context, viewId));
+
+        if (this.isClayTemplate(context, viewId)) {
+           int i = actionUrl.lastIndexOf(".");
+           if (i > -1) {
+              actionUrl.setLength(i);
+              actionUrl.append(suffix);
+           }     
+        } 
+        
+        return actionUrl.toString();
+    }
+
+    // Specified by ViewHandler
+    public String getResourceURL(FacesContext context, String path) {
+        return original.getResourceURL(context, path);
+    }
+
+    /**
+     * <p>Returns <code>true</code> if the <code>viewId</code> has a
+     * matching <code>suffix</code>.  The <code>suffix</code> is determined
+     * by an initialization parameter in the web deployment descriptor,
+     * <code>clay-template-suffix</code>.  The default suffix, if one
+     * is not specified, is ".clay".
+     * </p> 
+     */
+    protected boolean isClayTemplate(FacesContext context, String viewId) {
+        if (suffix == null) {
+            suffix = (String) context.getExternalContext().getInitParameter(
+                    Globals.CLAY_TEMPLATE_SUFFIX);
+            if (suffix == null) {
+                suffix = Globals.CLAY_DEFAULT_TEMPLATE_SUFFIX;
+            }
+        }
+        
+        return viewId.endsWith(suffix);
+    }
+
+    /**
+     * <p>The default view handler implementation will try to
+     * make the viewId end with ".jsp".  If the viewId ends
+     * in the clay template suffix, use the state manager
+     * to restore the view.</p>  
+     */
+    public UIViewRoot restoreView(FacesContext context, String viewId) {
+        UIViewRoot view = null;
+        
+        if (this.isClayTemplate(context, viewId)) {
+            
+            if (log.isInfoEnabled())
+                log.info("Clay template restoreView for " + viewId);
+                        
+            StateManager stateManager = context.getApplication().getStateManager();
+            view = stateManager.restoreView(context, viewId, calculateRenderKitId(context));
+        } else
+           view = original.restoreView(context, viewId);
+        return view;
+    }
+
+    //  Specified by ViewHandler
+    public void writeState(FacesContext context) throws IOException {
+        original.writeState(context);
+    }
+    
+    /**
+     * <p>The <code>viewId</code> of the view will be check to see if it ends with the 
+     * same suffix as the configured clay-template-suffix.  If a match is not found, 
+     * control is passed to the decorated view handler.  Otherwise, a {@link Clay} component 
+     * is instantiated as a single subtree under the view root. The component's <code>id</code>
+     * property is set with a constant, <code>CLAY_VIEW_ID</code>.  The <code>jsfid</code> 
+     * property is set to the <code>viewId</code>.  The <code>managedBeanName</code> property 
+     * is set with the Shale <code>ViewControllerMapper</code>.  A <code>ResponseWriter</code> 
+     * is created and rendering is invoked on the component.  This differs from the base implementation. 
+     * The base implementation would dispatch to a JSP that would assemble the component tree 
+     * and invoke rendering to the response writer.</p>
+     */
+    public void renderView(FacesContext context, UIViewRoot view)
+            throws IOException, FacesException {
+
+        //is this view a clay html template view
+        if (isClayTemplate(context, view.getViewId())) {
+            
+            if (log.isInfoEnabled())
+                log.info("Clay template renderView for " + view.getViewId());
+            
+            //look to see if it already exists 
+            UIComponent component = view.findComponent(CLAY_VIEW_ID);
+            if (component == null) {
+               component = context.getApplication().createComponent(CLAY_COMPONENT_TYPE);
+              ((Clay) component).setId(CLAY_VIEW_ID);
+              ((Clay) component).setJsfid(view.getViewId());
+              ((Clay) component).setManagedBeanName(getManagedBeanName(context, view.getViewId()));
+              view.getChildren().add(view.getChildren().size(), component);
+            } 
+            
+            //get the response
+            ServletResponse response = (ServletResponse) context.getExternalContext().getResponse();
+            //set the locale
+            (response).setLocale(context.getViewRoot().getLocale());
+            
+            //create a response writer
+            ResponseWriter responsewriter = context.getRenderKit().createResponseWriter(response.getWriter(), null, response.getCharacterEncoding());
+            //push it to the faces context
+            context.setResponseWriter(responsewriter);
+            //start a document
+            responsewriter.startDocument();
+      
+            recursiveRender(view, context);
+
+            //end the document
+            responsewriter.endDocument();
+
+            //save the view 
+            StateManager stateManager = context.getApplication().getStateManager();
+            StateManager.SerializedView serializedview = stateManager.saveSerializedView(context);
+
+           
+        } else {
+           //dispatch (forward) to the jsp
+           original.renderView(context, view);
+        }
+    }
+      
+    
+    /**
+     * <p>
+     * Recursively invokes the rendering of the sub component tree.
+     * </p>
+     */
+    protected void recursiveRender(UIComponent child,
+            FacesContext context) throws IOException {
+        
+        if (!child.getRendersChildren()) {
+            child.encodeBegin(context);
+            Iterator ci = child.getChildren().iterator();
+            while (ci.hasNext()) {
+                UIComponent c = (UIComponent) ci.next();
+                c.encodeBegin(context);
+                
+                if (!c.getRendersChildren())
+                    recursiveRender(c, context);
+                else
+                    c.encodeChildren(context);
+                
+                c.encodeEnd(context);
+                c = null;
+            }
+            child.encodeEnd(context);
+        } else {
+            // let the component handle iterating over the children
+            child.encodeBegin(context);
+            child.encodeChildren(context);
+            child.encodeEnd(context);
+        }
+    }    
+    
+    /**
+     * <p>Returns the managed-bean-name the view controller is registered under.  The
+     * assumed mapping will be the same as in core Shale</p>
+     */
+    protected String getManagedBeanName(FacesContext context, String viewId) {
+        if (mapper == null) {
+            mapper = (ViewControllerMapper)
+              context.getExternalContext().getApplicationMap().
+              get(ShaleConstants.VIEW_MAPPER);
+            
+            if (mapper == null)
+               mapper = new DefaultViewControllerMapper();
+        }
+        return mapper.mapViewId(viewId);
+    }
+
+
+
+}

Modified: struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java (original)
+++ struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/Parser.java Fri Jul 15 21:37:46 2005
@@ -254,7 +254,8 @@
                 } else {
                     // the current node is a optional and the new node is it's parent
                     // simulate having ending nodes
-                    if (this.isValidOptionalEndingTagParent(current.getName(), node.getName())) {
+                    
+                    if (isOptionalEndingTag(node.getName()) && isValidOptionalEndingTagParent(current.getName(), node.getName())) {
                         
                         pop: while (true) {
                             if (current == null)
@@ -283,6 +284,7 @@
                         }
                         
                     } else {
+                    
                        // adding a new node to the current making it current
                        current.addChild(node);
                        current = node;
@@ -432,7 +434,7 @@
                 // find the node name delimiter
                 int e = token.getDocument().indexOf(" ", token.getBeginOffset() + 2);
                 // end of token is the delimiter
-                if (e == -1 || e > token.getEndOffset())
+                if (e == -1 || e >= token.getEndOffset())
                     e = (isBeginTag && isEndTag) ? (token.getEndOffset() - 2)
                             : (token.getEndOffset() - 1);
                     // find the start of the node attribute body

Modified: struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommandButtonBuilder.java
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommandButtonBuilder.java?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommandButtonBuilder.java (original)
+++ struts/shale/trunk/clay-plugin/src/java/org/apache/shale/clay/parser/builder/CommandButtonBuilder.java Fri Jul 15 21:37:46 2005
@@ -60,6 +60,20 @@
     protected String getComponentType(Node node) {
         return "javax.faces.HtmlCommandButton";
     }
+
+    /**
+     * <p>Add the <code>value</code> attribute as a "HTML" attribute. For the
+     * commandButton, the value holds the label.</p>
+     */
+    protected String[] getHtmlAttributes() {
+        
+        String[] tmp = super.getHtmlAttributes();
+        String[] attrs = new String[tmp.length + 1];
+        System.arraycopy(tmp, 0, attrs, 0, tmp.length);
+        attrs[attrs.length - 1] = "value";
+        
+        return attrs;
+    }
  
         
 }

Modified: struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java (original)
+++ struts/shale/trunk/clay-plugin/src/test/org/apache/shale/clay/parser/ParserTestCase.java Fri Jul 15 21:37:46 2005
@@ -23,63 +23,62 @@
 
 public class ParserTestCase extends TestCase {
 
-    
     /**
-     * <p>Tests to see if we can parse a document fragment
-     * that has multiple root nodes</p>
+     * <p>
+     * Tests to see if we can parse a document fragment that has multiple root
+     * nodes
+     * </p>
      */
     public void testManyRootNodes() {
         Parser p = new Parser();
         StringBuffer doc1 = new StringBuffer();
 
-        doc1.append("<p>")
-            .append("<input type=text size=10 maxsize=10 id=username>")
-            .append("<input type=text size=10 maxsize=10 id=password>")
-            .append("</p>")
-            .append("<p>")
-            .append("This is a test.  Just a test")
-            .append("</p>")
-            .append("<p></p>");
-        
+        doc1.append("<p>").append(
+                "<input type=text size=10 maxsize=10 id=username>").append(
+                "<input type=text size=10 maxsize=10 id=password>").append(
+                "</p>").append("<p>").append("This is a test.  Just a test")
+                .append("</p>").append("<p></p>");
+
         List nodes1 = p.parse(doc1);
         assertTrue("Has 3 root nodes", nodes1.size() == 3);
-        
+
     }
-  
+
     /**
-     * <p>Test a couple comment block scenarios</p> 
+     * <p>
+     * Test a couple comment block scenarios
+     * </p>
      */
     public void testCommentBlocks() {
         Parser p = new Parser();
         StringBuffer doc1 = new StringBuffer();
 
-       
-        doc1.append("<p>")
-            .append("<!--<input type=text size=10 maxsize=10 id=username>")
-            .append("<input type=text size=10 maxsize=10 id=password>-->")
-            .append("</p>")
-            .append("<!--This is a test.  Just a test-->")
-            .append("<!--<p>Testing <b>123</b></p>-->");
-        
+        doc1.append("<p>").append(
+                "<!--<input type=text size=10 maxsize=10 id=username>").append(
+                "<input type=text size=10 maxsize=10 id=password>-->").append(
+                "</p>").append("<!--This is a test.  Just a test-->").append(
+                "<!--<p>Testing <b>123</b></p>-->");
+
         List nodes1 = p.parse(doc1);
-        assertTrue("Has 3 root nodes", nodes1.size() == 3);  
-        
+        assertTrue("Has 3 root nodes", nodes1.size() == 3);
+
         Node node = (Node) nodes1.get(0);
-        assertTrue("first paragraph has 1 node", node.getChildren().size() == 1);        
+        assertTrue("first paragraph has 1 node", node.getChildren().size() == 1);
 
         node = (Node) node.getChildren().get(0);
-        assertTrue("first comment block has 2 nodes", node.getChildren().size() == 2);        
+        assertTrue("first comment block has 2 nodes",
+                node.getChildren().size() == 2);
 
         node = (Node) nodes1.get(1);
-        assertTrue("second root has 0 child nodes", node.getChildren().size() == 0);        
+        assertTrue("second root has 0 child nodes",
+                node.getChildren().size() == 0);
 
         node = (Node) nodes1.get(2);
-        assertTrue("third root has 1 child node", node.getChildren().size() == 1);        
-   
-        
+        assertTrue("third root has 1 child node",
+                node.getChildren().size() == 1);
+
     }
-    
-    
+
     /**
      * <p>
      * Tests case insensitivity in parsing the document.
@@ -213,6 +212,52 @@
 
     }
 
+    /**
+     * Checks to see if nested tables parse correctly
+     */
+public void testNestedTables() {
+        Parser p = new Parser();
+        StringBuffer doc = new StringBuffer();
+        doc
+                .append("<table>")
+                .append("<tr><td><table><tr><td></td></tr></table></td>")
+                .append("<td><span jsfid=\"tabs\"><ul id=\"menu\"><li id=\"nav\"><a href=\"#\">Tab 1</a></li><li id=\"nav-sel\"><a href=\"#\">Tab 2</a></li><li id=\"nav\"><a href=\"#\">Tab 3</a></li></ul></span>")
+                .append("</td></tr>").append("</table>")
+                .append("<div id=\"contents\">")
+                .append("<table border=\"0\">")
+                .append("<tr><td rowspan=\"3\">")
+                .append("<span jsfid=\"contactTable\">")
+                .append("<table class=\"contacts\">")
+                .append("<tr class=\"contactsHeader\">              ")
+                .append("<td>")
+                .append("Contacts")
+                .append("</td>")
+                .append("</tr>    ")
+                .append("<tr class=\"contactsRow1\">")
+                .append("<td>")
+                .append("<a href=\"#\">ABC Company</a>")
+                .append("</td>")
+                .append("</tr>")   
+                .append("<tr class=\"contactsRow2\">")
+                .append("<td>")
+                .append("<a href=\"#\">XYZ Company</a>")
+                .append("</td>")
+                .append("</tr>")  
+                .append("</table>")
+                .append("</span>")  
+                .append("</td></tr>")
+                .append("<tr><td>")
+                .append("<table>")
+                .append("<tr><td><label style=\"color:#99CC66\" jsfid=\"contactNameLabel\">Name:</label></td><td><input jsfid=\"contactName\" type=text size=40 maxlength=\"50\"/></td><td><span style=\"color:red\" jsfid=\"contactNameMessage\">Mock Error Name</span></td></tr></table></td></tr>")
+                .append("</table>")
+                .append("</div>");
+        
+        
+        List nodes = p.parse(doc);
+        assertTrue("Well-formed nested table has 1 root node", nodes.size() == 2);
+
+
+    }
     /**
      * <p>
      * Aserts that two trees of parsed HTML have the same number children and

Modified: struts/shale/trunk/default.properties
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/default.properties?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/default.properties (original)
+++ struts/shale/trunk/default.properties Fri Jul 15 21:37:46 2005
@@ -29,11 +29,24 @@
 # a binary distribution of the JavaServer Faces Reference Implementation
 jsfri.dir=/usr/local/jsf-1_1_01
 
+# Version Identifier to append to artifact filenames, and embed in
+# JavaDoc comments
+project.version=0.2
+
+# Location in which state saving should take place (client or server)
+state.saving=client
+
+
 # Fully qualified pathname of the directory containing the "dist" output
 # of a build of the standalone version of Tiles (currently in the Struts
 # Sandbox).
 tiles.dir=${root.dir}/../sandbox/tiles/core-library/dist
 
+# Uncomment the following to compile and execute with MyFaces
+# rather than the JSF Reference Implementation
+#use.myfaces=true
+
+
 
 # ------------------------ Optional Customizations -----------------------
 
@@ -46,8 +59,28 @@
 # ----------------------- Standard Values --------------------------------
 
 
+# State for the "debug" attribute of the "javac" task
+compile.debug=true
+
+# State for the "deprecation" attribute of the "javac" task
+compile.deprecation=true
+
+# State for the "optimize" attribute of the "javac" task
+compile.optimize=true
+
+# FindBugs Output File
+findbugs.outputFile=${root.dir}/find-bugs.html
+
 # Name of the library repository directory into which we will download
 # our dependencies
 lib.dir=${root.dir}/lib
 
+# State for the "halt on error" attribute for JUnit tests
+test.haltonerror=true
+
+# State for the "halt on failure" attribute for JUnit tests
+test.haltonfailure=true
+
+# JUnit test execution engine
+test.runner=junit.textui.TestRunner
 

Modified: struts/shale/trunk/use-cases/src/java/org/apache/shale/usecases/view/Bundle.properties
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/use-cases/src/java/org/apache/shale/usecases/view/Bundle.properties?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/use-cases/src/java/org/apache/shale/usecases/view/Bundle.properties (original)
+++ struts/shale/trunk/use-cases/src/java/org/apache/shale/usecases/view/Bundle.properties Fri Jul 15 21:37:46 2005
@@ -128,7 +128,8 @@
 usecases.tiles=Tiles
 usecases.tiles.simple=A Simple Tiles Example
 usecases.clay=Clay View Use Cases
-usecases.rolodex=Rolodex Example
+usecases.rolodex1=Rolodex Example (JSP View)
+usecases.rolodex2=Rolodex Example (HTML View)
 
 # Validation
 validate.test.title=Shale Validation using Commons Validator

Modified: struts/shale/trunk/use-cases/src/web/WEB-INF/clay-config.xml
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/use-cases/src/web/WEB-INF/clay-config.xml?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/use-cases/src/web/WEB-INF/clay-config.xml (original)
+++ struts/shale/trunk/use-cases/src/web/WEB-INF/clay-config.xml Fri Jul 15 21:37:46 2005
@@ -25,7 +25,7 @@
     </element>      
   </component>	
 
-  <component jsfid="contactTable" extends="dataTable">
+  <component jsfid="contactTable" extends="dataTable" allowBody="false">
     <attributes>
       <set name="value" useValueLateBinding="true" value="#{managed-bean-name.contactsForTab}"/>
       <set name="var"   value="e"/>
@@ -240,7 +240,7 @@
 
 
 
-    <!-- Concat Name -->
+    <!-- Contact Name -->
 	<component jsfid="nameLabel" extends="baseLabel"> 
 		   <attributes>
 			  <set name="value" value="Name:" />		
@@ -292,8 +292,6 @@
 	<component jsfid="residentialPhone" extends="inputText" id="residentialPhone"> 
 		   <attributes>
 		      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.residentialPhone}" />		
-			  <set name="size" value="20" />
-			  <set name="maxlength" value="50" />
 			  <set name="required" value="false" />
 		   </attributes>
 	</component>
@@ -313,8 +311,6 @@
 	<component jsfid="businessPhone" extends="inputText" id="businessPhone"> 
 		   <attributes>
 		      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.businessPhone}" />		
-			  <set name="size" value="20" />
-			  <set name="maxlength" value="50" />
 			  <set name="required" value="false" />
 		   </attributes>
 	</component>
@@ -435,5 +431,358 @@
 
     </component>
 
-		
+
+<!--  HTML hroledex.html template -->
+
+    <!-- Nested Clay Component -->    
+	<component jsfid="tabs" extends="clay" id="tabs" allowBody="false">
+		<attributes>
+            <set name="jsfid" value="RUNTIME"/>
+            <set name="managedBeanName" value="rolodex$hrolodex"/>
+            <set name="shapeValidator" useMethodLateBinding="true" value="#{managed-bean-name.createTabs}"/> 
+		</attributes>
+    </component>	
+
+    <!-- submit button to save a contact -->
+    <component jsfid="contactSaveCommand" extends="commandButton"> 
+	   <attributes>
+		  <set name="action" value="#{managed-bean-name.saveContact}"/>	
+          <set name="rendered" useValueLateBinding="true" value="#{!empty managed-bean-name.selectedContact}"/>
+	   </attributes>
+    </component>
+
+    <!-- submit button to delete a contact -->
+    <component jsfid="contactDeleteCommand" extends="commandButton"> 
+	   <attributes>
+		  <set name="action" value="#{managed-bean-name.deleteContact}"/>
+          <set name="rendered" useValueLateBinding="true" value="#{!empty managed-bean-name.selectedContact}"/>	
+	   </attributes>
+    </component>
+
+    <!-- submit button to new a contact -->
+    <component jsfid="contactNewCommand" extends="commandButton"> 
+	   <attributes>
+		  <set name="action" value="#{managed-bean-name.newContact}"  />	
+          <set name="immediate" value="true"/>    
+	   </attributes>
+    </component>
+
+
+    <!-- Contact Name -->
+	<component jsfid="contactNameLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="contactName" />
+		   </attributes>
+	</component>				
+	<component jsfid="contactName" extends="inputText" id="contactName"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.name}" />		
+			  <set name="required" value="true" />
+		   </attributes>
+	</component>
+	<component jsfid="contactNameMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="contactName" />		
+		   </attributes>
+	</component>
+
+    <!-- Contact email address -->
+	<component jsfid="contactEmailLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="contactEmail" />
+		   </attributes>
+	</component>				
+	<component jsfid="contactEmail" extends="inputText" id="contactEmail"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.email}" />		
+			  <set name="required" value="false" />
+		   </attributes>
+	</component>
+	<component jsfid="contactEmailMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="contactEmail" />		
+		   </attributes>
+	</component>
+
+	<!-- residential city -->
+	<component jsfid="residentialCityLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="residentialCity" />
+		   </attributes>
+	</component>				
+	<component jsfid="residentialCity" extends="inputText" id="residentialCity"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.residentialAddress.city}" />		
+			  <set name="required" value="true" />
+		   </attributes>
+	</component>
+	<component jsfid="residentialCityMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="residentialCity" />		
+		   </attributes>
+	</component>
+
+
+	<!-- business city -->
+	<component jsfid="businessCityLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="businessCity" />
+		   </attributes>
+	</component>				
+	<component jsfid="businessCity" extends="inputText" id="businessCity"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.businessAddress.city}" />		
+			  <set name="required" value="true" />
+		   </attributes>
+	</component>
+	<component jsfid="businessCityMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="businessCity" />		
+		   </attributes>
+	</component>
+
+
+	<!-- residential street 1 label, input field and message -->
+	<component jsfid="residentialStreet1Label" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="residentialStreet1" />
+		   </attributes>
+	</component>				
+	<component jsfid="residentialStreet1" extends="inputText" id="residentialStreet1"> 
+        <attributes>
+		   <set name="value" value="#{managed-bean-name.selectedContact.residentialAddress.street1}" />		
+		   <set name="required" value="false"  />		
+		</attributes>
+	</component>
+	<component jsfid="residentialStreet1Message" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="residentialStreet1" />		
+		   </attributes>
+	</component>
+
+	<!-- business street 1 label, input field and message -->
+	<component jsfid="businessStreet1Label" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="businessStreet1" />
+		   </attributes>
+	</component>				
+	<component jsfid="businessStreet1" extends="inputText" id="businessStreet1"> 
+        <attributes>
+		   <set name="value" value="#{managed-bean-name.selectedContact.businessAddress.street1}" />		
+		   <set name="required" value="false"  />		
+		</attributes>
+	</component>
+	<component jsfid="businessStreet1Message" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="businessStreet1" />		
+		   </attributes>
+	</component>
+
+
+	<!-- residential street 2 label, input field and message -->
+	<component jsfid="residentialStreet2Label" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="residentialStreet2" />
+		   </attributes>
+	</component>				
+	<component jsfid="residentialStreet2" extends="inputText" id="residentialStreet2"> 
+        <attributes>
+		   <set name="value" value="#{managed-bean-name.selectedContact.residentialAddress.street2}" />		
+		   <set name="required" value="false"  />		
+		</attributes>
+	</component>
+	<component jsfid="residentialStreet2Message" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="residentialStreet2" />		
+		   </attributes>
+	</component>
+
+	<!-- business street 2 label, input field and message -->
+	<component jsfid="businessStreet2Label" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="businessStreet2" />
+		   </attributes>
+	</component>				
+	<component jsfid="businessStreet2" extends="inputText" id="businessStreet2"> 
+        <attributes>
+		   <set name="value" value="#{managed-bean-name.selectedContact.businessAddress.street2}" />		
+		   <set name="required" value="false"  />		
+		</attributes>
+	</component>
+	<component jsfid="businessStreet2Message" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="businessStreet2" />		
+		   </attributes>
+	</component>
+
+
+	<!-- residential state label, input field and message -->	
+	<component jsfid="residentialStateLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="residentialState" />
+		   </attributes>
+	</component>				
+	<component jsfid="residentialState" extends="selectOneMenu" id="residentialState" allowBody="false"> 
+       <attributes>
+	      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.residentialAddress.state}" />
+		  <set name="required" value="true" />	      
+ 	   </attributes>
+ 
+	   <element renderId="0" jsfid="selectItems"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{rolodexDao.states}" />
+ 	       </attributes>
+	   </element>
+	</component>
+	<component jsfid="residentialStateMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="residentialState" />		
+		   </attributes>
+	</component>
+
+
+	<!-- business state label, input field and message -->	
+	<component jsfid="businessStateLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="businessState" />
+		   </attributes>
+	</component>				
+	<component jsfid="businessState" extends="selectOneMenu" id="businessState" allowBody="false"> 
+       <attributes>
+	      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.businessAddress.state}" />
+		  <set name="required" value="true" />	      
+ 	   </attributes>
+ 
+	   <element renderId="0" jsfid="selectItems"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{rolodexDao.states}" />
+ 	       </attributes>
+	   </element>
+	</component>
+	<component jsfid="businessStateMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="businessState" />		
+		   </attributes>
+	</component>
+
+
+	<!-- residential zip code label, input field and message -->
+	<component jsfid="residentialZipLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="residentialZip" />
+		   </attributes>
+	</component>					
+	<component jsfid="residentialZip" id="residentialZip" extends="inputText"> 
+       <attributes>
+	      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.residentialAddress.zip}" />
+		</attributes>	
+		<converter jsfid="integerConverter" />
+	</component> 
+	<component jsfid="residentialZipMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="residentialZip" />		
+		   </attributes>
+	</component>
+
+	<!-- business zip code label, input field and message -->
+	<component jsfid="businessZipLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="businessZip" />
+		   </attributes>
+	</component>					
+	<component jsfid="businessZip" id="businessZip" extends="inputText"> 
+       <attributes>
+	      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.businessAddress.zip}" />
+		</attributes>	
+		<converter jsfid="integerConverter" />
+	</component> 
+	<component jsfid="businessZipMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="businessZip" />		
+		   </attributes>
+	</component>
+
+
+
+   <!-- Contact residential Phone -->
+	<component jsfid="contactResidentialPhoneLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="contactResidentialPhone" />
+		   </attributes>
+	</component>				
+	<component jsfid="contactResidentialPhone" extends="inputText" id="contactResidentialPhone"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.residentialPhone}" />		
+			  <set name="required" value="false" />
+		   </attributes>
+	</component>
+	<component jsfid="contactResidentialPhoneMessage" extends="message" allowBody="false" > 
+		   <attributes>
+		      <set name="for" value="contactResidentialPhone" />		
+		   </attributes>
+	</component>
+
+   <!-- Contact business Phone -->
+	<component jsfid="contactBusinessPhoneLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="contactBusinessPhone" />
+		   </attributes>
+	</component>				
+	<component jsfid="contactBusinessPhone" extends="inputText" id="contactBusinessPhone"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.businessPhone}" />		
+			  <set name="required" value="false" />
+		   </attributes>
+	</component>
+	<component jsfid="contactBusinessPhoneMessage" extends="message" allowBody="false" > 
+		   <attributes>
+		      <set name="for" value="contactBusinessPhone" />		
+		   </attributes>
+	</component>
+
+
+	<!-- business province label, input field and message -->	
+	<component jsfid="businessProvinceLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="businessProvince" />
+		   </attributes>
+	</component>				
+	<component jsfid="businessProvince" extends="inputText" id="businessProvince"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.businessAddress.province}" />		
+			  <set name="required" value="false" />
+		   </attributes>
+	</component>
+	<component jsfid="businessProvinceMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="businessProvince" />		
+		   </attributes>
+	</component>
+
+
+	<!-- business country label, input field and message -->	
+	<component jsfid="businessCountryLabel" extends="outputLabel" allowBody="true"> 
+		   <attributes>
+			  <set name="for"   value="businessCountry" />
+		   </attributes>
+	</component>				
+	<component jsfid="businessCountry" extends="selectOneMenu" id="businessCountry" allowBody="false"> 
+       <attributes>
+	      <set name="value" useValueLateBinding="true" value="#{managed-bean-name.selectedContact.businessAddress.country}" />
+		  <set name="required" value="true" />	      
+ 	   </attributes>
+ 
+	   <element renderId="0" jsfid="selectItems"> 
+		   <attributes>
+		      <set name="value" useValueLateBinding="true" value="#{rolodexDao.countries}" />
+ 	       </attributes>
+	   </element>
+	</component>
+	<component jsfid="businessCountryMessage" extends="message" allowBody="false"> 
+		   <attributes>
+		      <set name="for" value="businessCountry" />		
+		   </attributes>
+	</component>
+
+
 </view>

Modified: struts/shale/trunk/use-cases/src/web/WEB-INF/faces-config.xml
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/use-cases/src/web/WEB-INF/faces-config.xml?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/use-cases/src/web/WEB-INF/faces-config.xml (original)
+++ struts/shale/trunk/use-cases/src/web/WEB-INF/faces-config.xml Fri Jul 15 21:37:46 2005
@@ -268,15 +268,59 @@
       <to-view-id>/usecases.jsp</to-view-id>
     </navigation-case>
 
+    <!-- JSP View -->
     <navigation-case>
+      <from-outcome>rolodex$test1</from-outcome>
+      <to-view-id>/rolodex/rolodex.jsp</to-view-id>
+    </navigation-case>  
+    <navigation-case>
+      <from-action>#{rolodex.selectContact}</from-action>
       <from-outcome>rolodex$test</from-outcome>
       <to-view-id>/rolodex/rolodex.jsp</to-view-id>
-    </navigation-case>
+    </navigation-case>  
+    <navigation-case>
+      <from-action>#{rolodex.saveContact}</from-action>
+      <from-outcome>rolodex$test</from-outcome>
+      <to-view-id>/rolodex/rolodex.jsp</to-view-id>
+    </navigation-case>  
+    <navigation-case>
+      <from-action>#{rolodex.deleteContact}</from-action>
+      <from-outcome>rolodex$test</from-outcome>
+      <to-view-id>/rolodex/rolodex.jsp</to-view-id>
+    </navigation-case>  
     <navigation-case>
+      <from-action>#{rolodex.newContact}</from-action>
       <from-outcome>rolodex$test</from-outcome>
       <to-view-id>/rolodex/rolodex.jsp</to-view-id>
+    </navigation-case>  
+
+    <!-- HTML View -->
+    <navigation-case>
+      <from-outcome>rolodex$test2</from-outcome>
+      <to-view-id>/rolodex/hrolodex.html</to-view-id>
+    </navigation-case>
+    <navigation-case>
+      <from-action>#{rolodex$hrolodex.selectContact}</from-action>
+      <from-outcome>rolodex$test</from-outcome>
+      <to-view-id>/rolodex/hrolodex.html</to-view-id>
+    </navigation-case>  
+    <navigation-case>
+      <from-action>#{rolodex$hrolodex.saveContact}</from-action>
+      <from-outcome>rolodex$test</from-outcome>
+      <to-view-id>/rolodex/hrolodex.html</to-view-id>
     </navigation-case>
-     
+    <navigation-case>
+      <from-action>#{rolodex$hrolodex.deleteContact}</from-action>
+      <from-outcome>rolodex$test</from-outcome>
+      <to-view-id>/rolodex/hrolodex.html</to-view-id>
+    </navigation-case>
+    <navigation-case>
+      <from-action>#{rolodex$hrolodex.newContact}</from-action>
+      <from-outcome>rolodex$test</from-outcome>
+      <to-view-id>/rolodex/hrolodex.html</to-view-id>
+    </navigation-case>
+
+  
   </navigation-rule>
 
   <navigation-rule>
@@ -507,6 +551,17 @@
        View controller for the rolodex usecase
     </description>
     <managed-bean-name>rolodex</managed-bean-name>
+    <managed-bean-class>
+      org.apache.shale.usecases.rolodex.Rolodex
+    </managed-bean-class>
+    <managed-bean-scope>session</managed-bean-scope>
+  </managed-bean>
+
+  <managed-bean>
+    <description>
+       View controller for the rolodex usecase
+    </description>
+    <managed-bean-name>rolodex$hrolodex</managed-bean-name>
     <managed-bean-class>
       org.apache.shale.usecases.rolodex.Rolodex
     </managed-bean-class>

Modified: struts/shale/trunk/use-cases/src/web/WEB-INF/web.xml
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/use-cases/src/web/WEB-INF/web.xml?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/use-cases/src/web/WEB-INF/web.xml (original)
+++ struts/shale/trunk/use-cases/src/web/WEB-INF/web.xml Fri Jul 15 21:37:46 2005
@@ -119,6 +119,12 @@
     <url-pattern>*.faces</url-pattern>
   </servlet-mapping>
 
+  <!-- JavaServer Faces Servlet Mapping for Clay HTML Full View --> 
+  <servlet-mapping>
+    <servlet-name>faces</servlet-name>
+    <url-pattern>*.html</url-pattern>
+  </servlet-mapping>
+
   <!-- Welcome File List -->
   <welcome-file-list>
     <welcome-file>index.jsp</welcome-file>

Added: struts/shale/trunk/use-cases/src/web/rolodex/hrolodex.html
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/use-cases/src/web/rolodex/hrolodex.html?rev=219287&view=auto
==============================================================================
--- struts/shale/trunk/use-cases/src/web/rolodex/hrolodex.html (added)
+++ struts/shale/trunk/use-cases/src/web/rolodex/hrolodex.html Fri Jul 15 21:37:46 2005
@@ -0,0 +1,272 @@
+<html>
+<head>
+<title>Rolodex Example Using Clay HTML Full-view Composition</title>
+
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<style type="text/css" media="screen">
+body {
+	margin : 10px;
+	font: Verdana, Helvetica, Arial;
+	padding: 0px;
+	background: #fff;
+}
+
+#menu {
+	border-bottom : 1px solid #ccc;
+	margin : 0;
+	padding-bottom : 19px;
+	padding-left : 10px;
+}
+
+#menu ul, #menu li	{
+	display : inline;
+	list-style-type : none;
+	margin : 0;
+	padding : 0;
+}
+
+	
+#menu a:link, #menu a:visited	{
+	background : #E8EBF0;
+	border : 1px solid #ccc;
+	color : #666;
+	float : left;
+	font-size : small;
+	font-weight : normal;
+	line-height : 14px;
+	margin-right : 8px;
+	padding : 2px 10px 2px 10px;
+	text-decoration : none;
+}
+
+#menu a:link.active, #menu a:visited.active	{
+	background : #fff;
+	border-bottom : 1px solid #fff;
+	color : #000;
+}
+
+#menu a:hover	{
+	color : #f00;
+}
+
+.contacts {
+   border: 1px solid #fff;
+}
+
+.contactsHeader {
+   text-align: center;
+   color: #99CC66;
+   background: #E5F2D9;   
+}
+
+.contactsRow2 {
+   text-align: left;
+   color: #99CC66;
+   background: #D9EEF2;   
+}
+
+.contactsRow1 {
+   text-align: left;
+   color: #99CC66;
+   background: #F1F7D4;   
+}
+	
+body.section-1 #menu li#nav-sel a {
+	background : #fff;
+	border-bottom : 1px solid #fff;
+	color : #000;
+}
+
+li#nav {
+	background : #red;
+	border-bottom : 1px solid #000;
+	color : #000;
+}
+
+#menu ul a:hover {
+	color : #f00 !important;
+}
+
+#contents {
+	background : #fff;
+	border : 1px solid #ccc;
+	border-top : none;
+	clear : both;
+	margin : 0px;
+	padding : 15px;
+}
+
+input.button {
+    width: 1in; 
+    text-align: center; 
+    color: #99CC66; 
+    font-size: 12px; 
+    font-style: normal; 
+    font-weight: bold
+}
+</style>
+</head>
+<body class="section-1">
+<form>
+<span jsfid="tabs">
+<ul id="menu">
+   <li id="nav"><a href="#">Tab 1</a></li>
+   <li id="nav-sel"><a href="#">Tab 2</a></li>
+   <li id="nav"><a href="#">Tab 3</a></li>   
+</ul>
+</span>
+<div id="contents">
+<table border="0">
+   <tr>
+      <td rowspan="3">
+           <span jsfid="contactTable">
+              <table class="contacts">
+                  <tr class="contactsHeader">
+                     <td>
+                         Contacts
+                     </td>
+                  </tr>
+                  <tr class="contactsRow1">
+                     <td>
+                        <a href="#">ABC Company</a>
+                     </td>
+                  </tr>   
+                  <tr class="contactsRow2">
+                     <td>
+                        <a href="#">XYZ Company</a>
+                     </td>
+                  </tr>   
+              </table>
+           </span>
+      </td>
+   </tr>
+   <tr>
+     <td>  
+        <table border="0">
+          <tr>
+              <td><label style="color:#99CC66" jsfid="contactNameLabel">Name:</label></td>
+              <td><input jsfid="contactName" type=text size="40" maxlength="50"></td>
+              <td><span style="color:red" jsfid="contactNameMessage">Mock Error Name</span></td>
+          </tr>
+          <tr>
+              <td><label style="color:#99CC66" jsfid="contactEmailLabel">Email:</label></td>
+              <td><input jsfid="contactEmail" type=text size="30" maxlength="50"></td>
+              <td><span style="color:red" jsfid="contactEmailMessage">Mock Error Email</span></td>
+          </tr>
+        </table>
+     </td>
+     <td>             
+        <input styleClass="button" class="button" class="button" type="submit" value="Save Contact" jsfid="contactSaveCommand"><br>
+        <input styleClass="button" class="button" type="submit" value="Delete Contact" jsfid="contactDeleteCommand"><br>
+        <input styleClass="button" class="button" type="submit" value="New Contact" jsfid="contactNewCommand"><br>     
+     </td>
+    </tr>
+    <tr>
+     <td>
+        <table border=0>
+           <tr class="contactsHeader">
+              <td colspan="3">Residential Address:</td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66"  jsfid=residentialStreet1Label>Address 1:</label></td>
+                <td><input jsfid="residentialStreet1" type=text size="35" maxlength="50"></td>
+                <td><span style="color:red" jsfid="residentialStreet1Message">Mock Error Address 1</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66"  jsfid=residentialStreet2Label>Address 2:</label></td>
+                <td><input jsfid="residentialStreet2" type=text size="35" maxlength="50"></td>
+                <td><span style="color:red" jsfid="residentialStreet2Message">Mock Error Address 2</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="residentialCityLabel">City:</label></td>
+                <td><input jsfid="residentialCity" type=text size="20" maxlength="30"></td>
+                <td><span style="color:red" jsfid="residentialCityMessage">Mock Error City</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="residentialStateLabel">State:</label></td>
+                <td><select jsfid="residentialState">
+                       <option>Mock State 1
+                       <option>Mock State 2
+                    </select>
+                </td>
+                <td><span style="color:red" jsfid="residentialStateMessage">Mock Error State</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="residentialZipLabel">Zip:</label></td>
+                <td><input jsfid="residentialZip" type=text size="5" maxlength="9"/></td>
+                <td><span style="color:red" jsfid="residentialZipMessage">Mock Error Zip</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="contactResidentialPhoneLabel">Phone:</label></td>
+                <td><input jsfid="contactResidentialPhone" type=text size="20" maxlength="50"/></td>
+                <td><span style="color:red" jsfid="contactResidentialPhoneMessage">Mock Error Phone</span></td>
+           </tr>
+           <tr>
+                <td colspan="2">&nbsp;</td>
+           </tr>                    
+           <tr>
+                <td colspan="2">&nbsp;</td>
+           </tr>                                                   
+        </table>
+     </td>
+     <td>
+        <table border=0>
+           <tr class="contactsHeader">
+              <td colspan="3">Business Address:</td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid=businessStreet1Label>Address 1:</label></td>
+                <td><input jsfid="businessStreet1" type=text size="35" maxlength="50"></td>
+                <td><span style="color:red" jsfid="businessStreet1Message">Mock Error Address 1</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid=businessStreet2Label>Address 2:</label></td>
+                <td><input jsfid="businessStreet2" type=text size="35" maxlength="50"></td>
+                <td><span style="color:red" jsfid="businessStreet2Message">Mock Error Address 2</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="businessCityLabel">City:</label></td>
+                <td><input jsfid="businessCity" type=text size="20" maxlength="30"></td>
+                <td><span style="color:red" jsfid="businessCityMessage">Mock Error City</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="businessStateLabel">State:</label></td>
+                <td><select jsfid="businessState">
+                       <option>Mock State 1
+                       <option>Mock State 2
+                    </select>
+                </td>
+                <td><span style="color:red" jsfid="businessStateMessage">Mock Error State</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="businessProvinceLabel">Province:</label></td>
+                <td><input jsfid="businessProvince" type=text size="20" maxlength="30"></td>
+                <td><span style="color:red" jsfid="businessProvinceMessage">Mock Error Province</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="businessZipLabel">Zip:</label></td>
+                <td><input jsfid="businessZip" type=text size="5" maxlength="9"/></td>
+                <td><span style="color:red" jsfid="businessZipMessage">Mock Error Zip</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="businessCountryLabel">Country:</label></td>
+                <td><select jsfid="businessCountry">
+                       <option>Mock Country 1
+                       <option>Mock Country 2
+                    </select>
+                </td>
+                <td><span jsfid="businessCountryMessage">Mock Error Country</span></td>
+           </tr>
+           <tr>
+                <td><label style="color:#99CC66" jsfid="contactBusinessPhoneLabel">Phone:</label></td>
+                <td><input jsfid="contactBusinessPhone" type="text" size="20" maxlength="50"/></td>
+                <td><span style="color:red" jsfid="contactBusinessPhoneMessage">Mock Error Phone</span></td>
+           </tr>                    
+        </table>
+     </td>
+  <tr>
+</table>
+</div>
+</form>
+</body>
+</html>
\ No newline at end of file

Modified: struts/shale/trunk/use-cases/src/web/usecases.jsp
URL: http://svn.apache.org/viewcvs/struts/shale/trunk/use-cases/src/web/usecases.jsp?rev=219287&r1=219286&r2=219287&view=diff
==============================================================================
--- struts/shale/trunk/use-cases/src/web/usecases.jsp (original)
+++ struts/shale/trunk/use-cases/src/web/usecases.jsp Fri Jul 15 21:37:46 2005
@@ -5,7 +5,7 @@
 
 <%--
 
- Copyright 2004-2005 The Apache Software Foundation.
+ Copyright 2004-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.
@@ -109,27 +109,10 @@
 
   </h:panelGrid>
 
-  <h1><h:outputText     value="#{messages['usecases.ajax']}"/></h1>
-
-  <h:panelGrid        columns="1">
-
-    <h:commandLink         id="ajaxCodeCompletion"
-                       action="ajax$completion">
-      <h:outputText     value="#{messages['usecases.completion']}"/>
-    </h:commandLink>
-
-  </h:panelGrid>
-
   <h1><h:outputText     value="#{messages['usecases.java']}"/></h1>
 
   <h:panelGrid        columns="1">
 
-    <h:outputLink          id="javaStateNames"
-                        value="list/stateNames.remote"
-                       target="_new">
-      <h:outputText     value="#{messages['usecases.states']}"/>
-    </h:outputLink>
-
     <h:outputLink          id="javaCategories"
                         value="list/supportedCategories.remote"
                        target="_new">
@@ -175,9 +158,15 @@
   <h1><h:outputText     value="#{messages['usecases.clay']}"/></h1>
   <h:panelGrid        columns="1">
 
-    <h:commandLink         id="rolodex"
-                       action="rolodex$test">
-      <h:outputText     value="#{messages['usecases.rolodex']}"/>
+    <h:commandLink         id="rolodex1"
+                       action="rolodex$test1">
+      <h:outputText     value="#{messages['usecases.rolodex1']}"/>
+    
+    </h:commandLink>
+
+    <h:commandLink         id="rolodex2"
+                       action="rolodex$test2">
+      <h:outputText     value="#{messages['usecases.rolodex2']}"/>
     
     </h:commandLink>
 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org