Revision: 320
Author:   tfenne
Date:     2006-06-18 07:07:13 -0700 (Sun, 18 Jun 2006)
ViewCVS:  http://svn.sourceforge.net/stripes/?rev=320&view=rev

Log Message:
-----------
Fix for STS-154: add a focus attribute to the form tag.

Modified Paths:
--------------
    trunk/examples/web/bugzooky/AddEditBug.jsp
    trunk/examples/web/bugzooky/BulkAddEditBugs.jsp
    trunk/examples/web/bugzooky/Login.jsp
    trunk/examples/web/bugzooky/Register.jsp
    trunk/examples/web/bugzooky/Register2.jsp
    trunk/stripes/resources/stripes.tld
    trunk/stripes/src/net/sourceforge/stripes/tag/FormTag.java
    trunk/stripes/src/net/sourceforge/stripes/tag/InputTagSupport.java
Modified: trunk/examples/web/bugzooky/AddEditBug.jsp
===================================================================
--- trunk/examples/web/bugzooky/AddEditBug.jsp  2006-06-12 11:03:05 UTC (rev 
319)
+++ trunk/examples/web/bugzooky/AddEditBug.jsp  2006-06-18 14:07:13 UTC (rev 
320)
@@ -12,7 +12,7 @@
 
         <stripes:errors/>
 
-        <stripes:form action="/examples/bugzooky/SingleBug.action">
+        <stripes:form action="/examples/bugzooky/SingleBug.action" 
focus="bug.shortDescription">
             <table class="leftRightForm">
                 <tr>
                     <th>Bug ID:</th>

Modified: trunk/examples/web/bugzooky/BulkAddEditBugs.jsp
===================================================================
--- trunk/examples/web/bugzooky/BulkAddEditBugs.jsp     2006-06-12 11:03:05 UTC 
(rev 319)
+++ trunk/examples/web/bugzooky/BulkAddEditBugs.jsp     2006-06-18 14:07:13 UTC 
(rev 320)
@@ -9,7 +9,7 @@
         <jsp:useBean id="personManager" scope="page"
                      
class="net.sourceforge.stripes.examples.bugzooky.biz.PersonManager"/>
 
-        <stripes:form action="/examples/bugzooky/MultiBug.action">
+        <stripes:form action="/examples/bugzooky/MultiBug.action" focus="">
             <stripes:errors/>
 
             <table class="display">

Modified: trunk/examples/web/bugzooky/Login.jsp
===================================================================
--- trunk/examples/web/bugzooky/Login.jsp       2006-06-12 11:03:05 UTC (rev 
319)
+++ trunk/examples/web/bugzooky/Login.jsp       2006-06-18 14:07:13 UTC (rev 
320)
@@ -10,7 +10,7 @@
                     <!-- Somewhat contrived example of using the errors tag 
'action' attribute. -->
                     <stripes:errors action="/examples/bugzooky/Login.action"/>
 
-                    <stripes:form action="/examples/bugzooky/Login.action">
+                    <stripes:form action="/examples/bugzooky/Login.action" 
focus="">
                         <table>
                             <tr>
                                 <td style="font-weight: bold;"><stripes:label 
for="username"/>:</td>

Modified: trunk/examples/web/bugzooky/Register.jsp
===================================================================
--- trunk/examples/web/bugzooky/Register.jsp    2006-06-12 11:03:05 UTC (rev 
319)
+++ trunk/examples/web/bugzooky/Register.jsp    2006-06-18 14:07:13 UTC (rev 
320)
@@ -7,7 +7,7 @@
 
         <stripes:errors globalErrorsOnly="true"/>
 
-        <stripes:form action="/examples/bugzooky/Register.action" 
method="POST">
+        <stripes:form action="/examples/bugzooky/Register.action" 
focus="first">
             <p>Please provide the following information:</p>
 
             <table class="leftRightForm">

Modified: trunk/examples/web/bugzooky/Register2.jsp
===================================================================
--- trunk/examples/web/bugzooky/Register2.jsp   2006-06-12 11:03:05 UTC (rev 
319)
+++ trunk/examples/web/bugzooky/Register2.jsp   2006-06-18 14:07:13 UTC (rev 
320)
@@ -5,7 +5,7 @@
 <stripes:layout-render name="/bugzooky/layout/standard.jsp" title="Register">
     <stripes:layout-component name="contents">
 
-        <stripes:form action="/examples/bugzooky/Register.action" 
method="POST">
+        <stripes:form action="/examples/bugzooky/Register.action" 
focus="user.password">
             <stripes:errors/>
 
             <p>Welcome ${actionBean.user.firstName}, please pick a 
password:</p>

Modified: trunk/stripes/resources/stripes.tld
===================================================================
--- trunk/stripes/resources/stripes.tld 2006-06-12 11:03:05 UTC (rev 319)
+++ trunk/stripes/resources/stripes.tld 2006-06-18 14:07:13 UTC (rev 320)
@@ -412,6 +412,17 @@
             <type>java.lang.Object</type>
         </attribute>
         <attribute>
+            <description>
+                The name of the form field that should receive focus when the 
page is loaded. Two
+                special values are recognized, 'first' and the empty string; 
these values cause
+                the form to set focus on the first element in the form.  If 
any value is set,
+                and the form has validation errors, the behaviour is altered 
and the first field
+                with validation errors is focused instead.
+            </description>
+            
<name>focus</name><required>false</required><rtexprvalue>true</rtexprvalue>
+            <type>java.lang.String</type>
+        </attribute>
+        <attribute>
             <description>A comma separated list of content types that it is 
acceptable to submit through this form. (HTML Pass-through)</description>
             
<name>accept</name><required>false</required><rtexprvalue>true</rtexprvalue>
         </attribute>

Modified: trunk/stripes/src/net/sourceforge/stripes/tag/FormTag.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/tag/FormTag.java  2006-06-12 
11:03:05 UTC (rev 319)
+++ trunk/stripes/src/net/sourceforge/stripes/tag/FormTag.java  2006-06-18 
14:07:13 UTC (rev 320)
@@ -22,6 +22,8 @@
 import net.sourceforge.stripes.util.CryptoUtil;
 import net.sourceforge.stripes.util.HtmlUtil;
 import net.sourceforge.stripes.util.Log;
+import net.sourceforge.stripes.validation.ValidationErrors;
+import net.sourceforge.stripes.validation.ValidationError;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -33,6 +35,7 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.List;
 
 /**
  * <p>Form tag for use with the Stripes framework.  Supports all of the HTML 
attributes applicable
@@ -45,6 +48,10 @@
     /** Log used to log error and debugging information for this class. */
     private static Log log = Log.getInstance(FormTag.class);
 
+    /** Stores the field name (or magic values ''/'first') to set focus on. */
+    private String focus;
+    private boolean focusSet = false;
+
     /** Stores the value of the action attribute before the context gets 
appended. */
     private String actionWithoutContext;
 
@@ -110,6 +117,12 @@
     /** Corresponding getter for 'beanclass', will always return null. */
     public Object getBeanclass() { return null; }
 
+    /** Sets the name of the field that should receive focus when the form is 
rendered. */
+    public void setFocus(String focus) { this.focus = focus; }
+    /** Gets the name of the field that should receive focus when the form is 
rendered. */
+    public String getFocus() { return focus; }
+
+
     ////////////////////////////////////////////////////////////
     // Additional attributes specific to the form tag
     ////////////////////////////////////////////////////////////
@@ -201,8 +214,15 @@
 
             writeCloseTag(getPageContext().getOut(), "form");
 
+            // Write out a warning if focus didn't find a field
+            if (this.focus != null && !this.focusSet) {
+                log.error("Form with action [", getAction(), "] has 'focus' 
set to '", this.focus,
+                          "', but did not find a field with matching name to 
set focus on.");
+            }
+
             // Clean up any state the container won't reset during tag pooling
             this.fieldsPresent.clear();
+            this.focusSet = false;
         }
         catch (IOException ioe) {
             throw new StripesJspException("IOException in 
FormTag.doEndTag().", ioe);
@@ -323,9 +343,45 @@
      */
     public void registerField(InputTagSupport tag) {
         this.fieldsPresent.put(tag.getName(), tag.getClass());
+        setFocusOnFieldIfRequired(tag);
     }
 
     /**
+     * Checks to see if the field should receive focus either because it is 
the named
+     * field for receiving focus, because it is the first field in the form 
(and first
+     * field focus was specified), or because it is the first field in error.
+     *
+     * @param tag the input tag being registered with the form
+     */
+    protected void setFocusOnFieldIfRequired(InputTagSupport tag) {
+        // Decide whether or not this field should be focused
+        if (this.focus != null && !this.focusSet) {
+            ActionBean bean = getActionBean();
+            ValidationErrors errors = bean == null ? null : 
bean.getContext().getValidationErrors();
+
+            // If there are validaiton errors, select the first field in error
+            if (errors != null && errors.size() > 0) {
+                List<ValidationError> fieldErrors = errors.get(tag.getName());
+                if (fieldErrors != null && fieldErrors.size() > 0) {
+                    tag.setFocus(true);
+                    this.focusSet = true;
+                }
+            }
+            // Else set the named field, or the first field if that's desired
+            else if (this.focus.equals(tag.getName())) {
+                    tag.setFocus(true);
+                    this.focusSet = true;
+            }
+            else if ("".equals(this.focus) || 
"first".equalsIgnoreCase(this.focus)) {
+                if ( !(tag instanceof InputHiddenTag) ) {
+                    tag.setFocus(true);
+                    this.focusSet = true;
+                }
+            }
+        }
+    }
+
+    /**
      * Gets the set of all field names for which fields have been refered 
withing the form up
      * until the point of calling this method. If this is called during 
doEndTag it will contain
      * all field names, if it is called during the body of the tag it will 
only contain the

Modified: trunk/stripes/src/net/sourceforge/stripes/tag/InputTagSupport.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/tag/InputTagSupport.java  
2006-06-12 11:03:05 UTC (rev 319)
+++ trunk/stripes/src/net/sourceforge/stripes/tag/InputTagSupport.java  
2006-06-18 14:07:13 UTC (rev 320)
@@ -25,10 +25,13 @@
 import net.sourceforge.stripes.validation.BooleanTypeConverter;
 
 import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
 import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
+import java.util.Random;
 import java.lang.reflect.Method;
+import java.io.IOException;
 
 /**
  * Parent class for all input tags in stripes.  Provides support methods for 
retrieving all the
@@ -40,6 +43,7 @@
 public abstract class InputTagSupport extends HtmlTagSupport {
     private String formatType;
     private String formatPattern;
+    private boolean focus;
 
     /** A list of the errors related to this input tag instance */
     protected List<ValidationError> fieldErrors;
@@ -221,7 +225,9 @@
      * is null, then the empty string will be returned.
      */
     protected String format(Object input) {
-        if (input == null) return "";
+        if (input == null) {
+            return "";
+        }
 
         FormatterFactory factory = 
StripesFilter.getConfiguration().getFormatterFactory();
         Formatter formatter = factory.getFormatter(input.getClass(),
@@ -323,8 +329,13 @@
                 this.errorRenderer.doAfterEndTag();
             }
 
+            if (this.focus) {
+                makeFocused();
+            }
+
             this.errorRenderer = null;
             this.fieldErrors = null;
+            this.focus = false;
 
             return result;
         }
@@ -333,6 +344,34 @@
         }
     }
 
+    /**
+     * Informs the tag that it should render JavaScript to ensure that it is 
focused
+     * when the page is loaded. If the tag does not have an 'id' attribute a 
random
+     * one will be created and set so that the tag can be located easily.
+     *
+     * @param focus true if focus is desired, false otherwise
+     */
+    public void setFocus(boolean focus) {
+        this.focus = focus;
+
+        if ( getId() == null ) {
+            setId(String.valueOf( new Random().nextInt() ));
+        }
+    }
+
+    /** Writes out a JavaScript string to set focus on the field as it is 
rendered. */
+    protected void makeFocused() throws JspException {
+        try {
+            JspWriter out = getPageContext().getOut();
+            out.write("<script type=\"text/javascript\"/>var 
z=document.getElementById('");
+            out.write(getId());
+            out.write("'); z.focus(); z.select();</script>");
+        }
+        catch (IOException ioe) {
+            throw new StripesJspException("Could not write javascript focus 
code to jsp writer.", ioe);
+        }
+    }
+
     /** Abstract method implemented in child classes instead of doEndTag(). */
     public abstract int doEndInputTag() throws JspException;
 
@@ -385,7 +424,6 @@
     /** Gets the HTML attribute of the same name. */
     public String getReadonly() { return get("readonly"); }
 
-
     public void setName(String name) { set("name", name); }
     public String getName() { return get("name"); }
 


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to