You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/08/26 23:31:32 UTC

svn commit: r689238 [2/3] - in /tapestry/tapestry5/trunk: src/site/apt/ src/site/apt/cookbook/ src/site/apt/guide/ tapestry-core/src/main/java/org/apache/tapestry5/ tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/ tapestry-core/src/main/j...

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentDefaultProvider.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentDefaultProvider.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentDefaultProvider.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentDefaultProvider.java Tue Aug 26 14:31:30 2008
@@ -59,6 +59,15 @@
      * @param resources
      * @return the translator, or null
      */
-    Translator defaultTranslator(String parameterName, ComponentResources resources);
+    FieldTranslator defaultTranslator(String parameterName, ComponentResources resources);
 
+    /**
+     * Provides a validator based on the bound parameter type.  If the property type of the parameter is not known, then
+     * a no-op validator is returned.
+     *
+     * @param parameterName
+     * @param resources
+     * @return the validator, possibly a no-op validator
+     */
+    FieldValidator defaultValidator(String parameterName, ComponentResources resources);
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldTranslatorSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldTranslatorSource.java?rev=689238&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldTranslatorSource.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldTranslatorSource.java Tue Aug 26 14:31:30 2008
@@ -0,0 +1,69 @@
+//  Copyright 2008 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.
+
+package org.apache.tapestry5.services;
+
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.Field;
+import org.apache.tapestry5.FieldTranslator;
+import org.apache.tapestry5.Translator;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Messages;
+
+import java.util.Locale;
+
+/**
+ * For a particular field, generates the default {@link org.apache.tapestry5.FieldTranslator} for the field.
+ */
+public interface FieldTranslatorSource
+{
+    /**
+     * Common shorthand for {@link #createDefaultTranslator(org.apache.tapestry5.Field, String,
+     * org.apache.tapestry5.ioc.Messages, java.util.Locale, Class, org.apache.tapestry5.ioc.AnnotationProvider)}.
+     *
+     * @param resources     of component who owns the parameter
+     * @param parameterName name of parameter used to determine the property type
+     * @return field translator, or null
+     */
+    FieldTranslator createDefaultTranslator(ComponentResources resources, String parameterName);
+
+    /**
+     * Creates a {@link org.apache.tapestry5.FieldTranslator} for the given property, or returns null if one can't be
+     * constructed. The return value is null if the property type is not known, or if there is no {@link
+     * org.apache.tapestry5.Translator} available from the {@link org.apache.tapestry5.services.TranslatorSource} that
+     * is appropriate for the property type.
+     *
+     * @param field               for which a translator is needed
+     * @param overrideId          id used when looking in the overrideMessages for a message override
+     * @param overrideMessages    location to look for overriding messages
+     * @param locale              to localize validation messages to
+     * @param propertyType        type of property editted by the field, used to select the Translator
+     * @param propertyAnnotations annotations on the property (not currently used)
+     * @return the field translator, or null
+     */
+    FieldTranslator createDefaultTranslator(Field field, String overrideId, Messages overrideMessages, Locale locale,
+                                            Class propertyType, AnnotationProvider propertyAnnotations);
+
+    /**
+     * Wraps a {@link org.apache.tapestry5.Translator} as a FieldTranslator.
+     */
+    FieldTranslator createTranslator(Field field, String overrideId, Messages overrideMessages, Locale locale,
+                                     Translator translator);
+
+    /**
+     * Creates a translator (used by the {@link org.apache.tapestry5.BindingConstants#TRANSLATE translate: binding
+     * prefix}).
+     */
+    FieldTranslator createTranslator(ComponentResources componentResources, String translatorName);
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValidatorDefaultSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValidatorDefaultSource.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValidatorDefaultSource.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/FieldValidatorDefaultSource.java Tue Aug 26 14:31:30 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry5.services;
 
+import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.Field;
 import org.apache.tapestry5.FieldValidator;
 import org.apache.tapestry5.ioc.AnnotationProvider;
@@ -42,4 +43,14 @@
      */
     FieldValidator createDefaultValidator(Field field, String overrideId, Messages overrideMessages, Locale locale,
                                           Class propertyType, AnnotationProvider propertyAnnotations);
+
+    /**
+     * A convienience for the full version; assumes that the resources are associated with a {@link
+     * org.apache.tapestry5.Field}.
+     *
+     * @param resources
+     * @param parameterName
+     * @return
+     */
+    FieldValidator createDefaultValidator(ComponentResources resources, String parameterName);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyEditContext.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyEditContext.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyEditContext.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyEditContext.java Tue Aug 26 14:31:30 2008
@@ -15,8 +15,8 @@
 package org.apache.tapestry5.services;
 
 import org.apache.tapestry5.Field;
+import org.apache.tapestry5.FieldTranslator;
 import org.apache.tapestry5.FieldValidator;
-import org.apache.tapestry5.Translator;
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.Messages;
 
@@ -50,9 +50,10 @@
     /**
      * Returns the translator appropriate for the field (this is based on the property type).
      *
-     * @see TranslatorDefaultSource
+     * @param field
+     * @see org.apache.tapestry5.services.TranslatorSource
      */
-    Translator getTranslator();
+    FieldTranslator getTranslator(Field field);
 
     /**
      * Returns the FieldValidator for the field.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Tue Aug 26 14:31:30 2008
@@ -187,6 +187,7 @@
         binder.bind(HiddenFieldLocationRules.class, HiddenFieldLocationRulesImpl.class);
         binder.bind(PageDocumentGenerator.class, PageDocumentGeneratorImpl.class);
         binder.bind(ResponseRenderer.class, ResponseRendererImpl.class);
+        binder.bind(FieldTranslatorSource.class, FieldTranslatorSourceImpl.class);
     }
 
     // ========================================================================
@@ -628,16 +629,16 @@
      * Contributes the basic set of named translators: <ul>  <li>string</li>  <li>byte</li> <li>integer</li>
      * <li>long</li> <li>float</li> <li>double</li> <li>short</li> </ul>
      */
-    public static void contributeTranslatorSource(MappedConfiguration<String, Translator> configuration)
+    public static void contributeTranslatorSource(Configuration<Translator> configuration)
     {
 
-        configuration.add("string", new StringTranslator());
-        configuration.add("byte", new ByteTranslator());
-        configuration.add("integer", new IntegerTranslator());
-        configuration.add("long", new LongTranslator());
-        configuration.add("float", new FloatTranslator());
-        configuration.add("double", new DoubleTranslator());
-        configuration.add("short", new ShortTranslator());
+        configuration.add(new StringTranslator());
+        configuration.add(new ByteTranslator());
+        configuration.add(new IntegerTranslator());
+        configuration.add(new LongTranslator());
+        configuration.add(new FloatTranslator());
+        configuration.add(new DoubleTranslator());
+        configuration.add(new ShortTranslator());
     }
 
     /**

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorSource.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorSource.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorSource.java Tue Aug 26 14:31:30 2008
@@ -17,7 +17,9 @@
 import org.apache.tapestry5.Translator;
 
 /**
- * A source for {@link Translator}s, either by name.
+ * A source for {@link Translator}s, either by name or by property type.
+ * <p/>
+ * The configuration for the service is an unordered collection of {@link org.apache.tapestry5.Translator}.
  */
 public interface TranslatorSource
 {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/test/TapestryTestCase.java Tue Aug 26 14:31:30 2008
@@ -434,7 +434,6 @@
 
                 return result;
             }
-
         };
 
         expect(transformation.findMethods(EasyMock.isA(MethodFilter.class))).andAnswer(answer);
@@ -575,7 +574,6 @@
     protected final void train_getFieldType(ClassTransformation transformation, String fieldName, String type)
     {
         expect(transformation.getFieldType(fieldName)).andReturn(type).atLeastOnce();
-
     }
 
     protected final void train_getId(ComponentResources resources, String id)
@@ -1098,11 +1096,62 @@
     protected final void train_isRequired(Field field, boolean required)
     {
         expect(field.isRequired()).andReturn(required);
-
     }
 
     protected final void train_getClientId(ClientElement element, String clientId)
     {
         expect(element.getClientId()).andReturn(clientId);
     }
+
+    protected final FieldTranslator mockFieldTranslator()
+    {
+        return newMock(FieldTranslator.class);
+    }
+
+
+    protected final Translator mockTranslator(String name, Class type)
+    {
+        Translator translator = mockTranslator();
+
+        train_getName(translator, name);
+        train_getType(translator, type);
+
+        return translator;
+    }
+
+    protected final void train_getName(Translator translator, String name)
+    {
+        expect(translator.getName()).andReturn(name).atLeastOnce();
+    }
+
+    protected final void train_getType(Translator translator, Class type)
+    {
+        expect(translator.getType()).andReturn(type).atLeastOnce();
+    }
+
+    protected final void train_createDefaultTranslator(FieldTranslatorSource source, ComponentResources resources,
+                                                       String parameterName, FieldTranslator translator)
+    {
+        expect(source.createDefaultTranslator(resources, parameterName)).andReturn(translator);
+    }
+
+    protected final TranslatorSource mockTranslatorSource()
+    {
+        return newMock(TranslatorSource.class);
+    }
+
+    protected final void train_get(TranslatorSource translatorSource, String name, Translator translator)
+    {
+        expect(translatorSource.get(name)).andReturn(translator).atLeastOnce();
+    }
+
+    protected final void train_getMessageKey(Translator translator, String messageKey)
+    {
+        expect(translator.getMessageKey()).andReturn(messageKey).atLeastOnce();
+    }
+
+    protected final void train_findByType(TranslatorSource ts, Class propertyType, Translator translator)
+    {
+        expect(ts.findByType(propertyType)).andReturn(translator);
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/datefield.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/datefield.js?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/datefield.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/datefield.js Tue Aug 26 14:31:30 2008
@@ -75,8 +75,8 @@
 
         var errorHandler = function(message)
         {
-            Tapestry.fieldError(this.field, message);
-            Tapestry.focus(this.field);
+            this.field.showValidationMessage(message);
+            this.field.activate();
         };
 
         this.sendServerRequest(this.parseURL, value, resultHandler, errorHandler);
@@ -120,7 +120,7 @@
 
         this.datePicker.onselect = function()
         {
-            var input = this.formatDate(this.datePicker.getDate());
+            var input = this.canonicalizeDate(this.datePicker.getDate());
 
             var resultHandler = function(result)
             {
@@ -133,16 +133,21 @@
 
             var errorHandler = function(message)
             {
-                Tapestry.fieldError(this.field, message);
-                Tapestry.focus(this.field);
+                this.field.showValidationMessage(message);
+                this.field.activate();
+
                 this.hidePopup();
-            }
+            };
 
             this.sendServerRequest(this.formatURL, input, resultHandler, errorHandler);
         }.bind(this);
     },
 
-    formatDate : function(date)
+    /**
+     * Reformats the date into a canoncialized format accepted on the server. The format
+     * is equivalent to M/d/yyyy. This format is used regardless of localization.
+     */
+    canonicalizeDate : function(date)
     {
         if (date == null) return "";
 
@@ -155,7 +160,7 @@
         this.popup.clonePosition(this.field, { offsetTop: this.field.getHeight() + 2 }).setStyle({ width: "", height: "" });
     },
 
-    /** Duration used when fading the popup in or out. */
+    /** Duration, in seconds, used when fading the popup in or out. */
 
     FADE_DURATION : .20,
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages.properties Tue Aug 26 14:31:30 2008
@@ -24,11 +24,10 @@
 # This is lousy as a default, since the pattern string is meaningless to the user. You should always override
 # this.
 regexp=%2$s does not match pattern '%1$s'.
+invalid-email='%2$s' is not a valid email address.
 
 # This is where the translator messages go.
 
-integer-format-exception=The input value '%s' is not parseable as an integer value.
-number-format-exception=The input value '%s' is not parseable as a numeric value.
+integer-format-exception=You must provide an integer value for %s.
+number-format-exception=You must provide a numeric value for %s.
 
-
-invalid-email='%2$s' is not a valid email address.
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_da.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_da.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_da.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_da.properties Tue Aug 26 14:31:30 2008
@@ -24,10 +24,7 @@
 # This is lousy as a default, since the pattern string is meaningless to the user. You should always override
 # this.
 regexp=%2$s opfylder ikke mønstret '%1$s'.
+invalid-email=%2$s er ikke en gyldig e-mail-adresse.
 
 # This is where the translator messages go.
 
-integer-format-exception=Værdien af %s er ikke et gyldigt heltal.
-number-format-exception=Værdien af %s er ikke et gyldigt tal.
-
-invalid-email=%2$s er ikke en gyldig e-mail-adresse.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_de_DE.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_de_DE.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_de_DE.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_de_DE.properties Tue Aug 26 14:31:30 2008
@@ -27,6 +27,3 @@
 
 # This is where the translator messages go.
 
-integer-format-exception=Die Eingabe '%s' ist kein Zahlenwert.
-number-format-exception=Die Eingabe '%s' ist kein numerischer Wert.
-

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fi_FI.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fi_FI.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fi_FI.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fi_FI.properties Tue Aug 26 14:31:30 2008
@@ -24,14 +24,6 @@
 # This is lousy as a default, since the pattern string is meaningless to the user. You should always override
 # this.
 regexp=%2$s ei vastaa merkkijonoa '%1$s'.
-
-# This is where the translator messages go.
-
-integer-format-exception=\"%s\" ei ole kokonaisluku.
-number-format-exception=\"%s\" ei ole numero.
-
 invalid-email='%2$s' ei ole s\u00E4hk\u00F6postiosoite.
 
-# The label/alt text for the icon that is displayed next to each field.
-
-icon-label=[Virhe]
\ No newline at end of file
+# This is where the translator messages go.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr_FR.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr_FR.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr_FR.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr_FR.properties Tue Aug 26 14:31:30 2008
@@ -24,11 +24,7 @@
 # This is lousy as a default, since the pattern string is meaningless to the user. You should always override
 # this.
 regexp=%2$s ne correspond pas a l'expression '%1$s'.
+invalid-email='%2$s' n'est pas une adresse courriel valide.
 
 # This is where the translator messages go.
 
-integer-format-exception=La valeur entrée '%s' n'est pas un entier.
-number-format-exception=The input value '%s' n'est pas une valeur numérique.
-
-
-invalid-email='%2$s' n'est pas une adresse courriel valide.
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_hr.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_hr.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_hr.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_hr.properties Tue Aug 26 14:31:30 2008
@@ -24,11 +24,8 @@
 # This is lousy as a default, since the pattern string is meaningless to the user. You should always override
 # this.
 regexp=%2$s je potrebno upisati u sljedećem obliku: '%1$s'.
+invalid-email='%2$s' nije valjana e-mail addresa.
 
 # This is where the translator messages go.
 
-integer-format-exception='%s' nije cijeli broj.
-number-format-exception='%s' nije numerička vrijednost.
-
 
-invalid-email='%2$s' nije valjana e-mail addresa.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_it.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_it.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_it.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_it.properties Tue Aug 26 14:31:30 2008
@@ -27,6 +27,3 @@
 
 # This is where the translator messages go.
 
-integer-format-exception=Il valore di '%s' deve essere un numero intero.
-number-format-exception=Il valore di '%s' deve essere un numero.
-

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_PT.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_PT.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_PT.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_PT.properties Tue Aug 26 14:31:30 2008
@@ -27,6 +27,3 @@
 
 # This is where the translator messages go.
 
-integer-format-exception=O valor '%s' n\u00e3o \u00e9 um valor inteiro.
-number-format-exception=O valor '%s' n\u00e3o \u00e9 um valor num\u00e9rico.
-

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ru.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ru.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ru.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ru.properties Tue Aug 26 14:31:30 2008
@@ -24,11 +24,8 @@
 # This is lousy as a default, since the pattern string is meaningless to the user. You should always override
 # this.
 regexp=%2$s не соответствует требуемому шаблону '%1$s'.
+invalid-email='%2$s' недействительный адрес электронной почты.
 
 # This is where the translator messages go.
 
-integer-format-exception='%s' должно быть целым числом.
-number-format-exception='%s' должно быть числом.
 
-
-invalid-email='%2$s' недействительный адрес электронной почты.
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_sv_SE.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_sv_SE.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_sv_SE.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_sv_SE.properties Tue Aug 26 14:31:30 2008
@@ -24,10 +24,7 @@
 # This is lousy as a default, since the pattern string is meaningless to the user. You should always override
 # this.
 regexp=%2$s matchar inte m\u00F6nstret '%1$s'.
+invalid-email='%2$s' \u00E4r inte en korrekt formad email-adress.
 
 # This is where the translator messages go.
 
-integer-format-exception=Angivna v\u00E4rdet '%s' kan inte tolkas som ett heltalsv\u00E4rde.
-number-format-exception=Angivna v\u00E4rdet '%s' kan inte tolkas som ett numeriskt v\u00E4rde.
-
-invalid-email='%2$s' \u00E4r inte en korrekt formad email-adress.
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_zh_CN.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_zh_CN.properties?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_zh_CN.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_zh_CN.properties Tue Aug 26 14:31:30 2008
@@ -21,10 +21,6 @@
 
 min-integer = %2$s\u7684\u6570\u503C\u4E0D\u80FD\u5C0F\u4E8E%1$d\u3002
 
-minimum-string-length = %2$s\u7684\u5185\u5BB9\u4E0D\u80FD\u5C11\u4E8E%1$s\u5B57\u7B26\u3002
-
-number-format-exception = \u8F93\u5165\u7684'%s'\u4E0D\u662F\u6570\u5B57.
-
 # We try to keep these consistent, with the constraint value (if applicable)
 # as the first parameter, and the field's label as the second parameter. Occasionally
 # we must use specific indexing when that's not the best order.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js Tue Aug 26 14:31:30 2008
@@ -14,19 +14,37 @@
 
 var Tapestry = {
 
-    /** Event, triggered on a Form element, to spur fields within the form to validate thier input. */
+    /** Event that allows observers to perform cross-form validation after individual
+     *  fields have performed their validation. The form element is passed as the
+     *  event memo. Observers may set the form's validationError property to true (which
+     *  will prevent form submission).
+     */
     FORM_VALIDATE_EVENT : "tapestry:formvalidate",
 
-    /** Event, triggered on a Form element, to allow callbacks to perpare for a form submission (this
-     * occurs after validation).
+    /** Event fired just before the form submits, to allow observers to make
+     *  final preparations for the submission, such as updating hidden form fields.
+     *  The form element is passed as the event memo. 
      */
     FORM_PREPARE_FOR_SUBMIT_EVENT : "tapestry:formprepareforsubmit",
 
     /**
-     * Form event fired after prepare.
+     *  Form event fired after prepare.
      */
     FORM_PROCESS_SUBMIT_EVENT : "tapestry:formprocesssubmit",
 
+    /** Event, triggered on a field element, to cause observers validate the format of the input, and potentially
+     *  reformat it. The field will be passed to observers as the event memo.  This event will be followed by
+     *  FIELD_VALIDATE_EVENT, if the field's value is non-blank. Observers may invoke Element.showValidationMessage()
+     *  to identify that the field is in error (and decorate the field and show a popup error message).
+     */
+    FIELD_FORMAT_EVENT : "tapestry:fieldformat",
+
+    /** Event, triggered on a field element, to cause observers to validate the input. The field will be passed
+     * to observers as the event memo.    Observers may invoke Element.showValidationMessage()
+     *  to identify that the field is in error (and decorate the field and show a popup error message).
+     */
+    FIELD_VALIDATE_EVENT : "tapestry:fieldvalidate",
+
     /** Event, triggered on the document object, which identifies the current focus element. */
     FOCUS_CHANGE_EVENT : "tapestry:focuschange",
 
@@ -36,8 +54,6 @@
     /** Time, in seconds, that console messages are visible. */
     CONSOLE_DURATION : 60,
 
-    FormEvent : Class.create(),
-
     FormEventManager : Class.create(),
 
     FieldEventManager : Class.create(),
@@ -64,7 +80,7 @@
     /** Find all elements marked with the "t-invisible" CSS class and hide()s them, so that
      * Prototype's visible() method operates correctly. This is invoked when the
      * DOM is first loaded, and AGAIN whenever dynamic content is loaded via the Zone
-     * mechanism.     In addition, adds a focus listener for each form element.
+     * mechanism. In addition, adds a focus listener for each form element.
      */
     onDomLoadedCallback : function()
     {
@@ -97,14 +113,14 @@
         });
     },
 
-    // Generalized initialize function for Tapestry, used to help minimize the amount of JavaScript
-    // for the page by removing redundancies such as repeated Object and method names. The spec
-    // is a hash whose keys are the names of methods of the Tapestry.Initializer object.
-    // The value is an array of arrays.  The outer arrays represent invocations
-    // of the method.  The inner array are the parameters for each invocation.
-    // As an optimization, the inner value may not be an array but instead
-    // a single value.
-
+    /* Generalized initialize function for Tapestry, used to help minimize the amount of JavaScript
+     * for the page by removing redundancies such as repeated Object and method names. The spec
+     * is a hash whose keys are the names of methods of the Tapestry.Initializer object.
+     * The value is an array of arrays.  The outer arrays represent invocations
+     * of the method.  The inner array are the parameters for each invocation.
+     * As an optimization, the inner value may not be an array but instead
+     * a single value.
+     */
     init : function(spec)
     {
         $H(spec).each(function(pair)
@@ -133,22 +149,38 @@
         });
     },
 
+    /** Formats and displays an error message on the console. */
     error : function (message, substitutions)
     {
         Tapestry.updateConsole("t-err", message, substitutions);
     },
 
+    /** Formats and displays a warning on the console. */
     warn : function (message, substitutions)
     {
         Tapestry.updateConsole("t-warn", message, substitutions);
     },
 
+    /** Formats and displays a debug message on the console, if Tapestry.DEBUG_ENABLED is true. */
     debug : function (message, substitutions)
     {
         if (Tapestry.DEBUG_ENABLED)
             Tapestry.updateConsole("t-debug", message, substitutions);
     },
 
+    /** Formats a message and updates the console. The console is virtual
+     *  when FireBug is not present, the messages float in the upper-left corner
+     *  of the page and fade out after a short period.  The background color identifies
+     *  the severity of the message (red for error, yellow for warnings, grey for debug).
+     *  Messages can be clicked, which removes the immediately.
+     *
+     * When FireBug is present, the error(), warn() and debug() methods do not invoke
+     * this; instead those functions are rewritten to write entries into the FireBug console.
+     *
+     * @param className to use for the div element in the console
+     * @param message message template
+     * @param substitutions interpolated into the message (if provided)
+     */
     updateConsole : function (className, message, substitutions)
     {
         if (substitutions != undefined)
@@ -181,23 +213,6 @@
 
     },
 
-    getFormEventManager : function(form)
-    {
-        form = $(form);
-
-        var manager = form.eventManager;
-
-        if (manager == undefined)
-            manager = new Tapestry.FormEventManager(form);
-
-        return manager;
-    },
-
-    fieldError : function(field, message)
-    {
-        this.getFieldEventManager(field).addDecorations(message);
-    },
-
     /**
      * Passed the JSON content of a Tapestry partial markup response, extracts
      * the script and stylesheet information.  JavaScript libraries and stylesheets are loaded,
@@ -216,62 +231,6 @@
         Tapestry.onDomLoadedCallback();
     },
 
-    // Adds a validator for a field.  A FieldEventManager is added, if necessary.
-    // The validator will be called only for non-blank values, unless acceptBlank is
-    // true (in most cases, acceptBlank is flase). The validator is a function
-    // that accepts the current field value as its first parameter, and a
-    // Tapestry.FormEvent as its second.  It can invoke recordError() on the event
-    // if the input is not valid.
-
-    addValidator : function(field, acceptBlank, validator)
-    {
-        this.getFieldEventManager(field).addValidator(acceptBlank, validator);
-    },
-
-    getFieldEventManager : function(field)
-    {
-        field = $(field);
-
-        var manager = field.fieldEventManager;
-
-        if (manager == undefined) manager = new Tapestry.FieldEventManager(field);
-
-        return manager;
-    },
-
-    /**
-     * Used with validation to see if an element is visible: i.e., it and all of its containers, up to the
-     * containing form, are all visible. Only deeply visible elements are subject to validation.
-     */
-    isDeepVisible : function(element)
-    {
-        // This started as a recursively defined method attach to Element, but was converted
-        // to a stand-alone as part of TAPESTRY-2424.
-
-        var current = $(element);
-
-        while (true)
-        {
-            if (! current.visible()) return false;
-
-            if (current.tagName == "FORM") break;
-
-            current = $(current.parentNode)
-        }
-
-        return true;
-    },
-
-    /** Focuses on a field, selecting its text. */
-    focus : function (field)
-    {
-        field = $(field);
-
-        if (field.focus) field.focus();
-
-        if (field.select) field.select();
-    },
-
     /**
      * Default function for handling Ajax-related failures.
      */
@@ -346,6 +305,152 @@
 
 };
 
+Element.addMethods(
+{
+
+    /**
+     * Works upward from the element, checking to see if the element is visible. Returns false
+     * if it finds an invisible container. Returns true if it makes it as far as a (visible) FORM element.
+     *
+     * Note that this only applies to the CSS definition of visible; it doesn't check that the element
+     * is scolled into view.
+     * 
+     * @param element to search up from
+     * @return true if visible (and containers visible), false if it or container are not visible
+     */
+    isDeepVisible : function(element)
+    {
+        var current = $(element);
+
+        while (true)
+        {
+            if (! current.visible()) return false;
+
+            if (current.tagName == "FORM") break;
+
+            current = $(current.parentNode)
+        }
+
+        return true;
+    }
+});
+
+Element.addMethods('FORM',
+{
+    /**
+     * Gets or creates the Tapestry.FormEventManager for the form.
+     *
+     * @param form form element
+     */
+    getFormEventManager : function(form)
+    {
+        var manager = form.eventManager;
+
+        if (manager == undefined)
+            manager = new Tapestry.FormEventManager(form);
+
+        return manager;
+    }
+});
+
+Element.addMethods(['INPUT', 'SELECT', 'TEXTAREA'],
+{
+    /**
+     * Invoked on a form element (INPUT, SELECT, etc.), gets or creates the
+     * Tapestry.FieldEventManager for that field.
+     *
+     * @param field field element
+     */
+    getFieldEventManager : function(field)
+    {
+        field = $(field);
+
+        var manager = field.fieldEventManager;
+
+        if (manager == undefined) manager = new Tapestry.FieldEventManager(field);
+
+        return manager;
+    },
+
+    /**
+     * Obtains the Tapestry.FieldEventManager and asks it to show
+     * the validation message.   Sets the element's validationError property to true.
+     * @param element
+     * @param message to display
+     */
+    showValidationMessage : function(element, message)
+    {
+        element = $(element);
+
+        element.validationError = true;
+        element.form.validationError = true;
+
+        element.getFieldEventManager().showValidationMessage(message);
+
+        return element;
+    },
+
+    /**
+     * Removes any validation decorations on the field, and
+     * hides the error popup (if any) for the field.
+     */
+    removeDecorations : function(element)
+    {
+        $(element).getFieldEventManager().removeDecorations();
+
+        return element;
+    },
+
+    /** Utility method to add a validator function as an observer as an event.
+     *
+     * @param element element to observe events on
+     * @param eventName name of event to observe
+     * @param validator function passed the field's value
+     */
+    addValidatorAsObserver : function(element, eventName, validator)
+    {
+        element.observe(eventName, function(event)
+        {
+            try
+            {
+                validator.call(this, $F(element));
+            }
+            catch (message)
+            {
+                element.showValidationMessage(message);
+            }
+        });
+
+        return element;
+    },
+
+    /**
+     * Adds a standard validator for the element, an observer of
+     * Tapestry.FIELD_VALIDATE_EVENT. The validator function will be
+     * passed the current field value and should throw an error message if
+     * the field's value is not valid.
+     * @param element field element to validate
+     * @param validator function to be passed the field value
+     */
+    addValidator : function(element, validator)
+    {
+        return element.addValidatorAsObserver(Tapestry.FIELD_VALIDATE_EVENT, validator);
+    },
+
+    /**
+     * Adds a standard validator for the element, an observer of
+     * Tapestry.FIELD_FORMAT_EVENT. The validator function will be
+     * passed the current field value and should throw an error message if
+     * the field's value is not valid.
+     * @param element field element to validate
+     * @param validator function to be passed the field value
+     */
+    addFormatValidator : function(element, validator)
+    {
+        return element.addValidatorAsObserver(Tapestry.FIELD_FORMAT_EVENT, validator);
+    }
+});
+
 /** Container of functions that may be invoked by the Tapestry.init() function. */
 Tapestry.Initializer = {
 
@@ -425,7 +530,7 @@
         {
             // Turn normal form submission off.
 
-            Tapestry.getFormEventManager(element).preventSubmission = true;
+            element.getFormEventManager().preventSubmission = true;
 
             // After the form is validated and prepared, this code will
             // process the form submission via an Ajax call.  The original submit event
@@ -441,21 +546,22 @@
 
         // Otherwise, assume it's just an ordinary link.
 
-        var handler = function(event)
+        element.observe("click", function(event)
         {
             Tapestry.ajaxRequest(element.href, successHandler);
 
             Event.stop(event);
-        };
-
-        element.observe("click", handler);
+        });
     },
 
     validate : function (field, specs)
     {
         field = $(field);
 
-        Tapestry.getFormEventManager(field.form);
+        // Force the creation of the form and field event managers.
+
+        $(field.form).getFormEventManager();
+        $(field).getFieldEventManager();
 
         specs.each(function(spec)
         {
@@ -474,6 +580,10 @@
                 return;
             }
 
+            // Pass the extend field, the provided message, and the constraint object
+            // to the Tapestry.Validator function, so that it can, typically, invoke
+            // field.addValidator().
+
             vfunc.call(this, field, message, constraint);
         });
     },
@@ -524,25 +634,8 @@
     }
 };
 
-// New methods added to Element.
-
-Tapestry.ElementAdditions = {
-    // This is added to all Elements, but really only applys to form control elements. This method is invoked
-    // when a validation error is associated with a field. This gives the field a chance to decorate itself, its label
-    // and its icon.
-    decorateForValidationError : function(element, message)
-    {
-        Tapestry.getFieldEventManager(element).addDecorations(message);
-    },
-
-    removeDecorations : function(element)
-    {
-        Tapestry.getFieldEventManager(element).removeDecorations();
-    }
-};
-
-Element.addMethods(Tapestry.ElementAdditions);
-
+// When FireBug is available, rewrite the error(), warn() and debug()
+// methods to make use of it.
 if (window.console)
 {
     var createlog = function (log)
@@ -563,50 +656,69 @@
 
 // Collection of field based functions related to validation. Each
 // function takes a field, a message and an optional constraint value.
+// Some functions are related to Translators and work on the format event,
+// other's are from Validators and work on the validate event.
 
 Tapestry.Validator = {
+
+    INT_REGEXP : /^(\+|-)?\d+$/,
+
+    FLOAT_REGEXP : /^(\+|-)?((\.\d+)|(\d+(\.\d*)?))$/,
+
     required : function(field, message)
     {
-        Tapestry.addValidator(field, true, function(value, event)
+        field.addFormatValidator(function(value)
         {
-            if (value.strip() == '')
-                event.recordError(message);
+            if (value.strip() == '') throw message;
+        });
+    },
+
+    /** Validate that the input is a numeric integer. */
+    integernumber : function(field, message)
+    {
+        field.addFormatValidator(function(value)
+        {
+            if (value != '' && ! value.match(Tapestry.Validator.INT_REGEXP)) throw message;
+        });
+    },
+
+    decimalnumber : function(field, message)
+    {
+        field.addFormatValidator(function(value)
+        {
+            if (value != '' && ! value.match(Tapestry.Validator.FLOAT_REGEXP)) throw message;
         });
     },
 
     minlength : function(field, message, length)
     {
-        Tapestry.addValidator(field, false, function(value, event)
+        field.addValidator(function(value)
         {
-            if (value.length < length)
-                event.recordError(message);
+            if (value.length < length) throw message;
         });
     },
 
     maxlength : function(field, message, maxlength)
     {
-        Tapestry.addValidator(field, false, function(value, event)
+        field.addValidator(function(value)
         {
-            if (value.length > maxlength)
-                event.recordError(message);
+            if (value.length > maxlength) throw message;
         });
     },
 
     min : function(field, message, minValue)
     {
-        Tapestry.addValidator(field, false, function(value, event)
+        field.addValidator(function(value)
         {
-            if (value < minValue)
-                event.recordError(message);
+            if (value < minValue) throw message;
         });
     },
 
     max : function(field, message, maxValue)
     {
-        Tapestry.addValidator(field, false, function(value, event)
+        field.addValidator(function(value)
         {
-            if (value > maxValue)
-                event.recordError(message);
+            if (value > maxValue) throw message;
         });
     },
 
@@ -614,46 +726,13 @@
     {
         var regexp = new RegExp(pattern);
 
-        Tapestry.addValidator(field, false, function(value, event)
+        field.addValidator(function(value)
         {
-            if (! regexp.test(value))
-                event.recordError(message);
+            if (! regexp.test(value)) throw message;
         });
     }
 };
 
-
-// A Tapestry.FormEvent is used when the form sends presubmit and submit events to
-// a FieldEventManager. It allows the associated handlers to indirectly invoke
-// the Form's invalidField() method, and it tracks a result flag (true for success ==
-// no field errors, false if any field errors).
-
-Tapestry.FormEvent.prototype = {
-
-    initialize : function(form)
-    {
-        this.form = $(form);
-        this.result = true;
-    },
-
-    // Invoked by a validator function (which is passed the event) to record an error
-    // for the associated field. The event knows the field and form and invoke's
-    // the (added) form method invalidField().  Sets the event's result field to false
-    // (i.e., don't allow the form to submit), and sets the event's error field to
-    // true.
-
-    recordError : function(message)
-    {
-        if (this.focusField == undefined)
-            this.focusField = this.field;
-
-        this.field.decorateForValidationError(message);
-
-        this.result = false;
-        this.error = true;
-    }
-};
-
 Tapestry.ErrorPopup.prototype = {
 
     // If the images associated with the error popup are overridden (by overriding Tapestry's default.css stylesheet),
@@ -672,7 +751,9 @@
         this.field = $(field);
 
         this.innerSpan = new Element("span");
-        this.outerDiv = $(new Element("div", { 'class' : 't-error-popup' })).update(this.innerSpan).hide();
+        this.outerDiv = $(new Element("div", {
+            'id' : this.field.id + ":errorpopup",
+            'class' : 't-error-popup' })).update(this.innerSpan).hide();
 
         var body = $$('BODY').first();
 
@@ -688,7 +769,7 @@
 
             this.outerDiv.hide();
 
-            Tapestry.focus(this.field);
+            this.field.activate();
 
             Event.stop(event);  // Should be domevent.stop(), but that fails under IE
         }.bindAsEventListener(this));
@@ -802,41 +883,46 @@
 
     handleSubmit : function(domevent)
     {
+        this.form.validationError = false;
+
+        var firstErrorField = null;
+
         // Locate elements that have an event manager (and therefore, validations)
         // and let those validations execute, which may result in calls to recordError().
 
-        var event = new Tapestry.FormEvent(this.form);
 
         this.form.getElements().each(function(element)
         {
             if (element.fieldEventManager != undefined)
             {
-                event.field = element;
-                element.fieldEventManager.validateInput(event);
+                // Ask the FEM to validate input for the field, which fires
+                // a number of events.
+                var error = element.fieldEventManager.validateInput();
 
-                if (event.abort) throw $break;
+                if (error && ! firstErrorField)
+                {
+                    firstErrorField = element;
+                }
             }
         });
 
         // Allow observers to validate the form as a whole.  The FormEvent will be visible
         // as event.memo.  The Form will not be submitted if event.result is set to false (it defaults
-        // to true).
+        // to true).  Still trying to figure out what should get focus from this
+        // kind of event.
 
-        this.form.fire(Tapestry.FORM_VALIDATE_EVENT, event);
+        this.form.fire(Tapestry.FORM_VALIDATE_EVENT, this.form);
 
-        if (! event.result)
+        if (this.form.validationError)
         {
-            // Calling focus() does not trigger this event, so we do it manually.
-            // Defer it long enough for the animations to start.
-
-            event.focusField.activate();
-
             Event.stop(domevent); // Should be domevent.stop(), but that fails under IE
 
+            if (firstErrorField) firstErrorField.activate();
+
             return;
         }
 
-        this.form.fire(Tapestry.FORM_PREPARE_FOR_SUBMIT_EVENT);
+        this.form.fire(Tapestry.FORM_PREPARE_FOR_SUBMIT_EVENT, this.form);
 
         // This flag can be set to prevent the form from submitting normally.
         // This is used for some Ajax cases where the form submission must
@@ -862,42 +948,22 @@
     initialize : function(field)
     {
         this.field = $(field);
+        this.field.fieldEventManager = this;
 
-        field.fieldEventManager = this;
-
-        this.validators = [ ];
-
-        var id = field.id;
+        var id = this.field.id;
         this.label = $(id + ':label');
         this.icon = $(id + ':icon');
 
         this.field.observe("blur", function()
         {
-            var event = new Tapestry.FormEvent(this.field.form);
-
-            // This prevents the field from taking focus if there is an error.
-            event.focusField = this.field;
-
-            event.field = this.field;
-
-            this.validateInput(event);
+            this.validateInput(false);
         }.bindAsEventListener(this));
     },
 
-    // Adds a validator.  acceptBlank is true if the validator should be invoked regardless of
-    // the value.  Usually acceptBlank is false, meaning that the validator will be skipped if
-    // the field's value is blank. The validator itself is a function that is passed the
-    // field's value and the Tapestry.FormEvent object.  When a validator invokes event.recordError(),
-    // any subsequent validators for that field are skipped.
-
-    addValidator : function(acceptBlank, validator)
-    {
-        this.validators.push([ acceptBlank, validator]);
-    },
-
-    // Removes decorations on the field and label (the "t-error" CSS class) and makes the icon
-    // invisible.  A field that has special decoration needs will override this method.
 
+    /** Removes validation decorations if present. Hides the ErrorPopup,
+     *  if it exists.
+     */
     removeDecorations : function()
     {
         this.field.removeClassName("t-error");
@@ -912,11 +978,14 @@
             this.errorPopup.hide();
     },
 
-    // Adds decorations to the field (including label and icon if present).
-    // event - the validation event
-    // message - error message
 
-    addDecorations : function(message)
+    /**
+     * Show a validation error message, which will add decorations to the
+     * field and it label, make the icon visible, and raise the
+     * field's Tapestry.ErrorPopup to show the message.
+     * @param message validation message to display
+     */
+    showValidationMessage : function(message)
     {
         this.field.addClassName("t-error");
 
@@ -935,40 +1004,41 @@
         this.errorPopup.showMessage(message);
     },
 
-
-    // Invoked from the Form's onsubmit event handler. Gets the fields value and invokes
-    // each validator (unless the value is blank) until a validator returns false. Validators
-    // should not modify the field's value.
-
-    validateInput : function(event)
+    /**
+     * Invoked when a form is submitted, or when leaving a field, to perform
+     * field validations. Field validations are skipped for disabled fields.
+     * If all validations are succesful, any decorations are removed. If any validation
+     * fails, an error popup is raised for the field, to display the validation
+     * error message.
+     *
+     * @return true if the field has a validation error
+     */
+    validateInput : function()
     {
         if (this.field.disabled) return;
 
-        if (! Tapestry.isDeepVisible(this.field)) return;
+        if (! this.field.isDeepVisible()) return;
 
-        var value = $F(event.field);
-        var isBlank = (value == '');
+        this.field.validationError = false;
 
-        event.error = false;
+        this.field.fire(Tapestry.FIELD_FORMAT_EVENT, this.field);
 
-        this.validators.each(function(tuple)
+        // If Format went ok, perhaps do the other validations.
+
+        if (! this.field.validationError)
         {
-            var acceptBlank = tuple[0];
-            var validator = tuple[1];
+            var value = $F(this.field);
 
-            if (acceptBlank || !isBlank)
-            {
+            if (value != '')
+                this.field.fire(Tapestry.FIELD_VALIDATE_EVENT, this.field);
+        }
 
-                validator(value, event);
+        // Lastly, if no validation errors were found, remove the decorations.
 
-                // event.error is set by Tapestry.FormEvent.recordError().
+        if (! this.field.validationError)
+            this.field.removeDecorations();
 
-                if (event.error) throw $break;
-            }
-        });
-
-        if (! event.error)
-            this.removeDecorations();
+        return this.field.validationError;
     }
 };
 
@@ -1072,7 +1142,7 @@
             // On a submission, if the fragment is not visible, then wipe out its
             // form submission data, so that no processing or validation occurs on the server.
 
-            if (! Tapestry.isDeepVisible(this.element))
+            if (! this.element.isDeepVisible())
                 this.hidden.value = "";
         }.bind(this));
     },
@@ -1116,7 +1186,6 @@
     }
 };
 
-
 Tapestry.FormInjector.prototype = {
 
     initialize: function(spec)

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ClientFormatDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ClientFormatDemo.tml?rev=689238&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ClientFormatDemo.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ClientFormatDemo.tml Tue Aug 26 14:31:30 2008
@@ -0,0 +1,5 @@
+<html t:type="border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+    <t:beaneditform object="this"/>
+
+</html>
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/EventMethodTranslate.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/EventMethodTranslate.tml?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/EventMethodTranslate.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/EventMethodTranslate.tml Tue Aug 26 14:31:30 2008
@@ -1,7 +1,7 @@
 <html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
     <h1>Event Handler Method Translate</h1>
 
-    <t:form>
+    <t:form clientvalidation="false">
 
         <t:errors/>
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/NullStrategyDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/NullStrategyDemo.tml?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/NullStrategyDemo.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/NullStrategyDemo.tml Tue Aug 26 14:31:30 2008
@@ -8,6 +8,7 @@
 
 
     <t:form>
+        <t:errors/>
         <t:textfield t:id="number" nulls="zero"/>
         <br/>
         <input type="submit" value="Update"/>

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/FieldComponent.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/FieldComponent.java?rev=689238&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/FieldComponent.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/FieldComponent.java Tue Aug 26 14:31:30 2008
@@ -0,0 +1,25 @@
+//  Copyright 2008 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.
+
+package org.apache.tapestry5;
+
+import org.apache.tapestry5.runtime.Component;
+
+/**
+ * Used in a few places where we need a mock for {@link org.apache.tapestry5.Field} and {@link
+ * org.apache.tapestry5.runtime.Component} simultanesouly.
+ */
+public interface FieldComponent extends Field, Component
+{
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java Tue Aug 26 14:31:30 2008
@@ -340,7 +340,7 @@
         clickAndWait(SUBMIT);
 
         assertTextPresent("[false]");
-        assertTextPresent("The input value 'foo' is not parseable as an integer value.");
+        assertTextPresent("You must provide an integer value for Hours.");
 
         assertAttribute("//input[@id='hours']/@value", "foo");
 
@@ -2182,4 +2182,22 @@
         start("BeanEditor BeanEditContext");
         assertTextPresent("Bean class from context is: " + RegistrationData.class.getName());
     }
+
+    /**
+     * TAPESTRY-2352
+     */
+    public void client_field_format_validation()
+    {
+        start("Client Format Validation");
+
+        type("amount", "abc");
+        type("quantity", "abc");
+
+        click(SUBMIT);
+
+        waitForCondition("selenium.browserbot.getCurrentWindow().document.getElementById('amount:errorpopup')", "5000");
+
+        assertText("//div[@id='amount:errorpopup']/span", "You must provide a numeric value for Amount.");
+        assertText("//div[@id='quantity:errorpopup']/span", "Provide quantity as a number.");
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ClientFormatDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ClientFormatDemo.java?rev=689238&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ClientFormatDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ClientFormatDemo.java Tue Aug 26 14:31:30 2008
@@ -0,0 +1,32 @@
+//  Copyright 2008 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.
+
+package org.apache.tapestry5.integration.app1.pages;
+
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.beaneditor.Validate;
+
+/**
+ * Demonstrates client-side field format validation.
+ */
+public class ClientFormatDemo
+{
+    @Property
+    @Validate("required,min=1")
+    private int quantity;
+
+    @Property
+    @Validate("required,min=0")
+    private float amount;
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Start.java Tue Aug 26 14:31:30 2008
@@ -62,6 +62,8 @@
 
     private static final List<Item> ITEMS = CollectionFactory.newList(
 
+            new Item("ClientFormatDemo", "Client Format Validation", "Client-side input format validation"),
+
             new Item("ShortGrid", "Short Grid",
                      "Grid where the number of claimed rows is less than the number of actual rows"),
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java Tue Aug 26 14:31:30 2008
@@ -48,7 +48,7 @@
      * interface.
      */
     @Target(
-            { PARAMETER, FIELD })
+            {PARAMETER, FIELD})
     @Retention(RUNTIME)
     @Documented
     public @interface Local
@@ -92,7 +92,7 @@
                 {
                     long elapsed = System.nanoTime() - startTime;
 
-                    log.info(String.format("Request time: %5.2f s -- %s", elapsed * 10E-9d, request.getPath()));
+                    log.info(String.format("Request time: %5.2f s -- %s", elapsed * 10E-10d, request.getPath()));
                 }
             }
         };

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/BindingFactoryTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/BindingFactoryTest.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/BindingFactoryTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/BindingFactoryTest.java Tue Aug 26 14:31:30 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -16,13 +16,13 @@
 
 import org.apache.tapestry5.Binding;
 import org.apache.tapestry5.ComponentResources;
-import org.apache.tapestry5.Translator;
+import org.apache.tapestry5.FieldTranslator;
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
 import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.TapestryException;
 import org.apache.tapestry5.services.BindingFactory;
-import org.apache.tapestry5.services.TranslatorSource;
+import org.apache.tapestry5.services.FieldTranslatorSource;
 import org.testng.annotations.Test;
 
 /**
@@ -65,15 +65,15 @@
     @Test
     public void translate_binding()
     {
-        Translator translator = mockTranslator();
-        TranslatorSource source = newMock(TranslatorSource.class);
+        FieldTranslator translator = mockFieldTranslator();
+        FieldTranslatorSource source = newMock(FieldTranslatorSource.class);
         ComponentResources resources = mockComponentResources();
         Location l = mockLocation();
 
         String description = "foo bar";
         String expression = "mock";
 
-        expect(source.get(expression)).andReturn(translator);
+        expect(source.createTranslator(resources, expression)).andReturn(translator);
 
         replay();
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/ValidateBindingFactoryTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/ValidateBindingFactoryTest.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/ValidateBindingFactoryTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/ValidateBindingFactoryTest.java Tue Aug 26 14:31:30 2008
@@ -16,23 +16,18 @@
 
 import org.apache.tapestry5.Binding;
 import org.apache.tapestry5.ComponentResources;
-import org.apache.tapestry5.Field;
+import org.apache.tapestry5.FieldComponent;
 import org.apache.tapestry5.FieldValidator;
+import org.apache.tapestry5.internal.test.InternalBaseTestCase;
 import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.internal.util.TapestryException;
 import org.apache.tapestry5.runtime.Component;
 import org.apache.tapestry5.services.BindingFactory;
 import org.apache.tapestry5.services.FieldValidatorSource;
-import org.apache.tapestry5.test.TapestryTestCase;
 import org.testng.annotations.Test;
 
-public class ValidateBindingFactoryTest extends TapestryTestCase
+public class ValidateBindingFactoryTest extends InternalBaseTestCase
 {
-    private interface FieldComponent extends Field, Component
-    {
-    }
-
-    ;
 
     @Test
     public void not_a_field()
@@ -72,7 +67,7 @@
         FieldValidatorSource source = mockFieldValidatorSource();
         ComponentResources container = mockComponentResources();
         ComponentResources component = mockComponentResources();
-        FieldComponent instance = newMock(FieldComponent.class);
+        FieldComponent instance = mockFieldComponent();
         Location l = mockLocation();
         FieldValidator validator = mockFieldValidator();
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDefaultProviderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDefaultProviderImplTest.java?rev=689238&r1=689237&r2=689238&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDefaultProviderImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDefaultProviderImplTest.java Tue Aug 26 14:31:30 2008
@@ -17,7 +17,7 @@
 import org.apache.tapestry5.Binding;
 import org.apache.tapestry5.BindingConstants;
 import org.apache.tapestry5.ComponentResources;
-import org.apache.tapestry5.Translator;
+import org.apache.tapestry5.FieldTranslator;
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
@@ -26,7 +26,7 @@
 import org.apache.tapestry5.runtime.Component;
 import org.apache.tapestry5.services.BindingSource;
 import org.apache.tapestry5.services.ComponentDefaultProvider;
-import org.apache.tapestry5.services.TranslatorSource;
+import org.apache.tapestry5.services.FieldTranslatorSource;
 import org.testng.annotations.Test;
 
 public class ComponentDefaultProviderImplTest extends InternalBaseTestCase
@@ -50,7 +50,7 @@
 
         replay();
 
-        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null, null, null);
+        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null, null, null, null);
 
         assertSame(provider.defaultLabel(resources), message);
 
@@ -74,7 +74,7 @@
 
         replay();
 
-        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null, null, null);
+        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null, null, null, null);
 
         assertEquals(provider.defaultLabel(resources), "My Field");
 
@@ -103,7 +103,7 @@
         replay();
 
         ComponentDefaultProvider source = new ComponentDefaultProviderImpl(access, bindingSource, null,
-                                                                           null);
+                                                                           null, null);
 
         assertNull(source.defaultBinding(parameterName, resources));
 
@@ -145,7 +145,7 @@
         replay();
 
         ComponentDefaultProvider source = new ComponentDefaultProviderImpl(access, bindingSource, null,
-                                                                           null);
+                                                                           null, null);
 
         assertSame(source.defaultBinding(parameterName, resources), binding);
 
@@ -155,14 +155,14 @@
     @Test
     public void default_translator_property_type_is_null()
     {
-        TranslatorSource source = mockTranslatorSource();
         ComponentResources resources = mockComponentResources();
+        FieldTranslatorSource source = newMock(FieldTranslatorSource.class);
 
-        train_getBoundType(resources, "object", null);
+        train_createDefaultTranslator(source, resources, "object", null);
 
         replay();
 
-        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null, null, source);
+        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null, null, source, null);
 
         assertNull(provider.defaultTranslator("object", resources));
 
@@ -172,21 +172,18 @@
     @Test
     public void default_translator()
     {
-        TranslatorSource source = mockTranslatorSource();
         ComponentResources resources = mockComponentResources();
-        Translator translator = mockTranslator();
+        FieldTranslator translator = mockFieldTranslator();
+        FieldTranslatorSource source = newMock(FieldTranslatorSource.class);
 
-        train_getBoundType(resources, "object", Integer.class);
-
-        expect(source.findByType(Integer.class)).andReturn(translator);
+        train_createDefaultTranslator(source, resources, "object", translator);
 
         replay();
 
-        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null, null, source);
+        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null, null, source, null);
 
         assertSame(provider.defaultTranslator("object", resources), translator);
 
         verify();
     }
-
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/FieldTranslatorSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/FieldTranslatorSourceImplTest.java?rev=689238&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/FieldTranslatorSourceImplTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/FieldTranslatorSourceImplTest.java Tue Aug 26 14:31:30 2008
@@ -0,0 +1,198 @@
+//  Copyright 2008 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.
+
+package org.apache.tapestry5.internal.services;
+
+import org.apache.tapestry5.*;
+import org.apache.tapestry5.internal.test.InternalBaseTestCase;
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.services.FieldTranslatorSource;
+import org.apache.tapestry5.services.FormSupport;
+import org.apache.tapestry5.services.TranslatorSource;
+import org.apache.tapestry5.services.ValidationMessagesSource;
+import org.testng.annotations.Test;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Fills in some gaps that are not currently tested by the integration tests.
+ */
+public class FieldTranslatorSourceImplTest extends InternalBaseTestCase
+{
+    @Test
+    public void create_default_property_type_null()
+    {
+        Field field = mockField();
+        Messages messages = mockMessages();
+        Locale locale = Locale.ENGLISH;
+
+        replay();
+
+        FieldTranslatorSource source = new FieldTranslatorSourceImpl(null, null, null);
+
+        assertNull(source.createDefaultTranslator(field, "override", messages, locale, null, null));
+
+        verify();
+    }
+
+    @Test
+    public void create_default_translator_not_found_for_type()
+    {
+        Field field = mockField();
+        Messages messages = mockMessages();
+        Locale locale = Locale.ENGLISH;
+        Class propertyType = Map.class;
+        TranslatorSource ts = mockTranslatorSource();
+
+        train_findByType(ts, propertyType, null);
+
+        replay();
+
+        FieldTranslatorSource source = new FieldTranslatorSourceImpl(ts, null, null);
+
+        assertNull(source.createDefaultTranslator(field, "override", messages, locale, propertyType, null));
+
+        verify();
+    }
+
+    @Test
+    public void create_default_translator_with_name()
+    {
+        Field field = mockField();
+        Messages messages = mockMessages();
+        Locale locale = Locale.ENGLISH;
+        Class propertyType = Map.class;
+        TranslatorSource ts = mockTranslatorSource();
+        ValidationMessagesSource vms = mockValidationMessagesSource();
+        FormSupport fs = mockFormSupport();
+        Translator translator = mockTranslator("maptrans", Map.class);
+        Messages validationMessages = mockMessages();
+        MessageFormatter formatter = mockMessageFormatter();
+        MarkupWriter writer = mockMarkupWriter();
+        String label = "Field Label";
+        String message = "Woops, did it again.";
+
+
+        train_findByType(ts, propertyType, translator);
+        train_contains(messages, "myfield-maptrans-message", false);
+        train_getValidationMessages(vms, locale, validationMessages);
+
+        train_getMessageKey(translator, "mykey");
+        train_getMessageFormatter(validationMessages, "mykey", formatter);
+        train_getLabel(field, label);
+        train_format(formatter, message, label);
+
+        translator.render(field, message, writer, fs);
+
+        replay();
+
+        FieldTranslatorSource source = new FieldTranslatorSourceImpl(ts, vms, fs);
+
+        FieldTranslator ft = source.createDefaultTranslator(field, "myfield", messages, locale, propertyType, null);
+
+        assertEquals(ft.getType(), Map.class);
+
+        ft.render(writer);
+
+        verify();
+    }
+
+    @Test
+    public void create_default_translator_with_override_message()
+    {
+        Field field = mockField();
+        Messages messages = mockMessages();
+        Locale locale = Locale.ENGLISH;
+        Class propertyType = Map.class;
+        TranslatorSource ts = mockTranslatorSource();
+        ValidationMessagesSource vms = mockValidationMessagesSource();
+        FormSupport fs = mockFormSupport();
+        Translator translator = mockTranslator("maptrans", Map.class);
+        MessageFormatter formatter = mockMessageFormatter();
+        MarkupWriter writer = mockMarkupWriter();
+        String label = "My Label";
+        String message = "Formatted Message";
+
+        train_findByType(ts, propertyType, translator);
+        train_contains(messages, "myfield-maptrans-message", true);
+        train_getMessageFormatter(messages, "myfield-maptrans-message", formatter);
+
+        train_getLabel(field, label);
+        train_format(formatter, message, label);
+
+        translator.render(field, message, writer, fs);
+
+        replay();
+
+        FieldTranslatorSource source = new FieldTranslatorSourceImpl(ts, vms, fs);
+
+        FieldTranslator ft = source.createDefaultTranslator(field, "myfield", messages, locale, propertyType, null);
+
+        assertEquals(ft.getType(), Map.class);
+
+        ft.render(writer);
+
+        verify();
+    }
+
+    @Test
+    public void create_translator_from_translator_name()
+    {
+        ComponentResources resources = mockComponentResources();
+        FieldComponent field = mockFieldComponent();
+        Messages messages = mockMessages();
+        Locale locale = Locale.ENGLISH;
+        TranslatorSource ts = mockTranslatorSource();
+        ValidationMessagesSource vms = mockValidationMessagesSource();
+        FormSupport fs = mockFormSupport();
+        Translator translator = mockTranslator("map", Map.class);
+        Messages validationMessages = mockMessages();
+        MessageFormatter formatter = mockMessageFormatter();
+        MarkupWriter writer = mockMarkupWriter();
+        String label = "My Label";
+        String message = "Formatted Message";
+
+        train_getComponent(resources, field);
+        train_getId(resources, "myfield");
+        train_getContainerMessages(resources, messages);
+        train_getLocale(resources, locale);
+
+        train_get(ts, "map", translator);
+        train_contains(messages, "myfield-map-message", false);
+        train_getValidationMessages(vms, locale, validationMessages);
+
+        train_getMessageKey(translator, "mykey");
+        train_getMessageFormatter(validationMessages, "mykey", formatter);
+
+
+        train_getLabel(field, label);
+        train_format(formatter, message, label);
+
+        translator.render(field, message, writer, fs);
+
+        replay();
+
+        FieldTranslatorSource source = new FieldTranslatorSourceImpl(ts, vms, fs);
+
+        FieldTranslator ft = source.createTranslator(resources, "map");
+
+        assertEquals(ft.getType(), Map.class);
+
+        ft.render(writer);
+
+        verify();
+    }
+}