You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2008/02/11 20:40:56 UTC

svn commit: r620592 - in /tapestry/tapestry5/trunk/tapestry-core: ./ src/main/java/org/apache/tapestry/corelib/components/ src/main/java/org/apache/tapestry/corelib/mixins/ src/main/java/org/apache/tapestry/grid/ src/main/java/org/apache/tapestry/servi...

Author: hlship
Date: Mon Feb 11 11:40:54 2008
New Revision: 620592

URL: http://svn.apache.org/viewvc?rev=620592&view=rev
Log:
TAPESTRY-2069: Replace LGPL JavaScript calendar with a properly licensed one

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/datefield.gif   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/datefield.js
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/css/
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/css/datepicker.css
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/images/
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/images/arrow.left.png   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/images/arrow.right.png   (with props)
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/js/
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/js/datepicker.js
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/jscalendar-1.0/
Modified:
    tapestry/tapestry5/trunk/tapestry-core/LICENSE.txt
    tapestry/tapestry5/trunk/tapestry-core/NOTICE.txt
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.xdoc
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/default.css
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/logging.apt
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/DateFieldDemo.tml
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/DateFieldTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/DateFieldDemo.java

Modified: tapestry/tapestry5/trunk/tapestry-core/LICENSE.txt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/LICENSE.txt?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/LICENSE.txt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/LICENSE.txt Mon Feb 11 11:40:54 2008
@@ -201,11 +201,17 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 
+-------------------------------------------------------------------------------
+
 This module, tapestry-core, includes a number of resources with seperate copyrights and licenses.
 
+-------------------------------------------------------------------------------
+
 JAVASSIST
 
-Javassist is not bundled with tapestry-core, but is bound to it.
+Javassist is not bundled with tapestry-core, but tapestry-core is not functional without Javassist.
+Javassist is bundled under a dual license: Mozilla Public License when distributed outside of JBoss,
+LGPL when distributed as part of JBoss.
 
 MOZILLA PUBLIC LICENSE
 Version 1.1
@@ -376,6 +382,7 @@
       Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL, and not to allow others to use your version of this file under the terms of the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of either the MPL or the LGPL.
 
 
+-------------------------------------------------------------------------------
 
 PROTOTYPE
 
@@ -396,6 +403,7 @@
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
+-------------------------------------------------------------------------------
 
 SCRIPTACULOUS
 
@@ -420,19 +428,10 @@
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+-------------------------------------------------------------------------------
 
-DYNARCH.COM DHTML/JAVASCRIPT CALENDAR
-
-The DHTML Calendar
--------------------
-
-  Author: Mihai Bazon, <mi...@yahoo.com>
-          http://dynarch.com/mishoo/
-
-  This program is free software published under the
-  terms of the GNU Lesser General Public License.
+WEBFX DATEPICKER
 
-  For the entire license text please refer to
-  http://www.gnu.org/licenses/lgpl.html
+Distributed under the terms of the Apache Software License 2.0.
   
   

Modified: tapestry/tapestry5/trunk/tapestry-core/NOTICE.txt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/NOTICE.txt?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/NOTICE.txt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/NOTICE.txt Mon Feb 11 11:40:54 2008
@@ -10,11 +10,11 @@
 This product includes the prototype JavaScript library, distributed under the terms of an MIT-style license.
 http://prototypejs.org/
 
-This product includes modified versions of Java classes from the JSON library.
+This product includes modified versions of Java classes from the JSON library, which is freely available.
 http://json.org/
 
-This product includes the DHTML/JavaScript Calendar, distributed under the terms of the Lesser GNU Public License.
-
+This product includes the WebFX DatePicker, a JavaScript library released under the Apache Software License 2.0
+http://webfx.eae.net/dhtml/datepicker/datepicker.html
 
 This product includes images from the Silk icon set, distributed under the terms of the Creative Commons Attribution 2.5 License.
 http://www.famfamfam.com/lab/icons/silk/

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java Mon Feb 11 11:40:54 2008
@@ -16,17 +16,18 @@
 
 import org.apache.tapestry.*;
 import org.apache.tapestry.annotations.Environmental;
+import org.apache.tapestry.annotations.IncludeJavaScriptLibrary;
+import org.apache.tapestry.annotations.IncludeStylesheet;
 import org.apache.tapestry.annotations.Parameter;
-import org.apache.tapestry.annotations.Path;
 import org.apache.tapestry.corelib.base.AbstractField;
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.ioc.annotations.Inject;
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
-import org.apache.tapestry.ioc.internal.util.TapestryException;
 import org.apache.tapestry.json.JSONObject;
 import org.apache.tapestry.services.FieldValidatorDefaultSource;
 import org.apache.tapestry.services.Request;
 
+import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -37,6 +38,8 @@
  * href="http://www.dynarch.com/projects/calendar/">dynarch.com DHTML/JavaScript Calendar</a>.
  */
 // TODO: More testing; see https://issues.apache.org/jira/browse/TAPESTRY-1844
+@IncludeStylesheet("${tapestry.datepicker}/css/datepicker.css")
+@IncludeJavaScriptLibrary({"${tapestry.datepicker}/js/datepicker.js", "datefield.js"})
 public class DateField extends AbstractField
 {
     /**
@@ -45,9 +48,6 @@
     @Parameter(required = true, principal = true)
     private Date _value;
 
-    @Parameter(defaultPrefix = "literal")
-    private String _format = "%m/%d/%y";
-
     /**
      * The object that will perform input validation (which occurs after translation). The translate binding prefix is
      * generally used to provide this object in a declarative fashion.
@@ -56,41 +56,8 @@
     @SuppressWarnings("unchecked")
     private FieldValidator<Object> _validate = NOOP_VALIDATOR;
 
-
-    /**
-     * If true, then the client-side calendar will show the time as well as the date.  You will probably need to bind
-     * the format parameter as well when this is true, say to <code>%m/%d/%y %H:%M</code>.
-     */
-    @Parameter
-    private boolean _editTime;
-
-    // We will eventually make the skins & themes more configurable.
-
-    @Inject
-    @Path("${tapestry.jscalendar}/skins/aqua/theme.css")
-    private Asset _themeStylesheet;
-
-    // Would be nice to use the stripped version when in production mode. Have to define "production
-    // mode" first.
-    @Inject
-    @Path("${tapestry.jscalendar}/calendar.js")
-    private Asset _mainScript;
-
-    // Their naming convention isn't our naming convention, so we're locked to the english
-    // version regardless of the application's current locale.
-
-    @Inject
-    @Path("${tapestry.jscalendar}/lang/calendar-en.js")
-    private Asset _localizationScript;
-
-    @Inject
-    @Path("${tapestry.jscalendar}/calendar-setup.js")
-    private Asset _setupScript;
-
-    // TODO: Make this more configurable
-    @Inject
-    @Path("${tapestry.jscalendar}/img.gif")
-    private Asset _defaultIcon;
+    @Parameter(defaultPrefix = "asset", value = "datefield.gif")
+    private Asset _icon;
 
     @Environmental
     private PageRenderSupport _support;
@@ -116,6 +83,8 @@
     @Inject
     private FieldValidationSupport _fieldValidationSupport;
 
+    private final DateFormat _format = new SimpleDateFormat("MM/dd/yy");
+
     /**
      * The default value is a property of the container whose name matches the component's id. May return null if the
      * container does not have a matching property.
@@ -139,9 +108,6 @@
 
     void beginRender(MarkupWriter writer)
     {
-        _support.addStylesheetLink(_themeStylesheet, null);
-        _support.addScriptLink(_mainScript, _localizationScript, _setupScript);
-
         String value = _tracker.getInput(this);
 
         if (value == null) value = formatCurrentValue();
@@ -149,8 +115,6 @@
         String clientId = getClientId();
         String triggerId = clientId + ":trigger";
 
-        // TODO: Support a disabled parameter
-
         writer.element("input",
 
                        "type", "text",
@@ -173,39 +137,26 @@
 
         // Now the trigger icon.
 
-        writer.element("button",
-
-                       "class", "t-calendar-trigger",
-
-                       "id", triggerId);
-
-        writeDisabled(writer);
+        writer.element("img",
 
+                       "id", triggerId,
 
-        writer.element("img",
+                       "class", "t-calendar-trigger",
 
-                       "src", _defaultIcon.toClientURL(),
+                       "src", _icon.toClientURL(),
 
                        "alt", "[Show]");
         writer.end(); // img
-        writer.end(); // button
 
         // The setup parameters passed to Calendar.setup():
 
         JSONObject setup = new JSONObject();
 
-        setup.put("inputField", clientId);
-        setup.put("ifFormat", _format);
-        setup.put("button", triggerId);
-
+        setup.put("field", clientId);
 
-        if (_editTime) setup.put("showsTime", true);
+        // TODO: consolodate DatePicker initialization across the page.
 
-        // Let subclasses do more.
-
-        configure(setup);
-
-        _support.addScript("Calendar.setup(%s);", setup);
+        _support.addScript("new Tapestry.DateField(%s);", setup);
     }
 
     private void writeDisabled(MarkupWriter writer)
@@ -213,23 +164,12 @@
         if (isDisabled()) writer.attributes("disabled", "disabled");
     }
 
-    /**
-     * Invoked to allow subclasses to further configure the parameters passed to the JavaScript Calendar.setup()
-     * function. The values inputField, ifFormat and button are pre-configured. Subclasses may override this method to
-     * configure additional features of the client-side Calendar. This implementation does nothing.
-     *
-     * @param setup parameters object
-     */
-    protected void configure(JSONObject setup)
-    {
-
-    }
 
     private String formatCurrentValue()
     {
         if (_value == null) return "";
 
-        return toJavaDateFormat().format(_value);
+        return _format.format(_value);
     }
 
     @Override
@@ -243,7 +183,9 @@
 
         try
         {
-            if (InternalUtils.isNonBlank(value)) parsedValue = toJavaDateFormat().parse(value);
+            if (InternalUtils.isNonBlank(value))
+                parsedValue =
+                        _format.parse(value);
 
         }
         catch (ParseException ex)
@@ -264,47 +206,6 @@
         }
     }
 
-    SimpleDateFormat toJavaDateFormat()
-    {
-        String format = _format;
-
-        StringBuilder builder = new StringBuilder();
-
-        int startx = 0;
-
-        while (true)
-        {
-            int nextx = format.indexOf('%', startx);
-
-            if (nextx < 0)
-            {
-                builder.append(format.substring(startx));
-                break;
-            }
-
-            builder.append(format.subSequence(startx, nextx));
-
-            char ch = format.charAt(nextx + 1);
-
-            String prefix = Character.isUpperCase(ch) ? "sym-up" : "sym-";
-
-            String key = prefix + ch;
-
-            if (!_messages.contains(key))
-            {
-                String message = _messages.format("unknown-symbol", ch, format);
-
-                throw new TapestryException(message, _resources.getLocation(), null);
-            }
-
-            builder.append(_messages.get(key));
-
-            startx = nextx + 2;
-        }
-
-        return new SimpleDateFormat(builder.toString());
-    }
-
     void injectResources(ComponentResources resources)
     {
         _resources = resources;
@@ -313,10 +214,5 @@
     void injectMessages(Messages messages)
     {
         _messages = messages;
-    }
-
-    void injectFormat(String format)
-    {
-        _format = format;
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java Mon Feb 11 11:40:54 2008
@@ -48,7 +48,7 @@
  * <p/>
  * When the form is submitted, the component emits several notifications: first a {@link #PREPARE_FOR_SUBMIT}, then a
  * {@link #PREPARE}: these allow the page to update its state as necessary to prepare for the form submission, then
- * (after components enclosed by the form have operated), a {@link #VALIDATE}event is emitted, to allow for cross-form
+ * (after components enclosed by the form have operated), a {@link #VALIDATE_FORM}event is emitted, to allow for cross-form
  * validation. After that, either a {@link #SUCCESS} OR {@link #FAILURE} event (depending on whether the {@link
  * ValidationTracker} has recorded any errors). Lastly, a {@link #SUBMIT} event, for any listeners that care only about
  * form submission, regardless of success or failure.
@@ -86,7 +86,7 @@
      * Event type for a notification to perform validation of submitted data. This allows a listener to perform
      * cross-field validation. This occurs before the {@link #SUCCESS} or {@link #FAILURE} notification.
      */
-    public static final String VALIDATE = "validate";
+    public static final String VALIDATE_FORM = "validateForm";
 
     /**
      * Event type for a notification after the form has submitted, when there are no errors in the validation tracker.
@@ -366,7 +366,7 @@
 
             _tracker = tracker;
 
-            _resources.triggerEvent(VALIDATE, context, callback);
+            _resources.triggerEvent(VALIDATE_FORM, context, callback);
 
             if (callback.isAborted()) return true;
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.xdoc
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.xdoc?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.xdoc (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.xdoc Mon Feb 11 11:40:54 2008
@@ -129,7 +129,7 @@
                 <ul>
                     <li>prepareForSubmit</li>
                     <li>prepare</li>
-                    <li>validate</li>
+                    <li>validateForm</li>
                     <li>failure
                         <em>or</em>
                         success
@@ -138,7 +138,7 @@
                 </ul>
 
                 <p>
-                    The validate event is to allow the page to
+                    The validateForm event is to allow the page to
                     perform cross-field validation. The failure or success
                     event is fired based on whether there are or are not any
                     validation errors.

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java Mon Feb 11 11:40:54 2008
@@ -15,10 +15,8 @@
 package org.apache.tapestry.corelib.mixins;
 
 import org.apache.tapestry.*;
-import org.apache.tapestry.annotations.Environmental;
-import org.apache.tapestry.annotations.InjectContainer;
-import org.apache.tapestry.annotations.Parameter;
-import org.apache.tapestry.annotations.Path;
+import org.apache.tapestry.ContentType;
+import org.apache.tapestry.annotations.*;
 import org.apache.tapestry.internal.services.ResponseRenderer;
 import org.apache.tapestry.internal.util.Holder;
 import org.apache.tapestry.ioc.annotations.Inject;
@@ -54,6 +52,7 @@
  * }
  * </pre>
  */
+@IncludeJavaScriptLibrary("${tapestry.scriptaculous}/controls.js")
 public class Autocomplete
 {
     static final String EVENT_NAME = "autocomplete";
@@ -82,10 +81,6 @@
     private MarkupWriterFactory _factory;
 
     @Inject
-    @Path("${tapestry.scriptaculous}/controls.js")
-    private Asset _controlsLibrary;
-
-    @Inject
     @Path("classpath:org/apache/tapestry/ajax-loader.gif")
     private Asset _loader;
 
@@ -112,11 +107,6 @@
      */
     @Parameter(defaultPrefix = "literal")
     private String _tokens;
-
-    void setupRender()
-    {
-        _pageRenderSupport.addScriptLink(_controlsLibrary);
-    }
 
     /**
      * Mixin afterRender phrase occurs after the component itself. This is where we write the &lt;div&gt;

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/grid/GridDataSource.java Mon Feb 11 11:40:54 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.
@@ -16,16 +16,12 @@
 
 import org.apache.tapestry.beaneditor.BeanModel;
 import org.apache.tapestry.beaneditor.PropertyModel;
-import org.apache.tapestry.corelib.components.Form;
 import org.apache.tapestry.corelib.components.Grid;
 
 /**
- * Defines how a {@link Grid} components (and its sub-components) gain access to the row data that
+ * Defines how a {@link Grid} component (and its sub-components) gain access to the row data that
  * is displayed on the page. In many cases, this is just a wrapper around a simple List, but the
  * abstractions exist to support access to a large data set that is accessible in sections.
- * <p/>
- * This interface is still under development, as we work out the best approach to handling a
- * {@link Grid} inside a {@link Form} using a large dataset.
  */
 public interface GridDataSource
 {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java Mon Feb 11 11:40:54 2008
@@ -178,14 +178,14 @@
                                                             @Symbol("tapestry.scriptaculous.path")
                                                             String scriptaculousPath,
 
-                                                            @Symbol("tapestry.jscalendar.path")
-                                                            String jscalendarPath)
+                                                            @Symbol("tapestry.datepicker.path")
+                                                            String datepickerPath)
     {
         configuration.add("tapestry", "org/apache/tapestry");
 
         configuration.add("scriptaculous", scriptaculousPath);
 
-        configuration.add("jscalendar", jscalendarPath);
+        configuration.add("datepicker", datepickerPath);
     }
 
     public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration)
@@ -1694,10 +1694,10 @@
         configuration.add("tapestry.scriptaculous", "classpath:${tapestry.scriptaculous.path}");
         configuration.add("tapestry.scriptaculous.path", "org/apache/tapestry/scriptaculous_1_8");
 
-        // Likewise for jscalendar, currently version 1.0
+        // Likewise for WebFX DatePicker, currently version 1.0.6
 
-        configuration.add("tapestry.jscalendar.path", "org/apache/tapestry/jscalendar-1.0");
-        configuration.add("tapestry.jscalendar", "classpath:${tapestry.jscalendar.path}");
+        configuration.add("tapestry.datepicker.path", "org/apache/tapestry/datepicker_106");
+        configuration.add("tapestry.datepicker", "classpath:${tapestry.datepicker.path}");
     }
 
     public PageTemplateLocator build(@ContextProvider AssetFactory contextAssetFactory,

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/datefield.gif
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/datefield.gif?rev=620592&view=auto
==============================================================================
Binary file - no diff available.

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/datefield.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/datefield.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/datefield.js?rev=620592&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/datefield.js (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/components/datefield.js Mon Feb 11 11:40:54 2008
@@ -0,0 +1,140 @@
+Tapestry.DateField = Class.create();
+
+Tapestry.DateField.prototype = {
+
+    // Initializes a DateField from a JSON specification.
+
+    initialize : function(spec)
+    {
+        this.field = $(spec.field);
+        this.trigger = $(spec.field + ":trigger");
+
+        this.trigger.observe("click", this.triggerClicked.bind(this));
+
+        this.popup = null;
+    },
+
+    triggerClicked : function()
+    {
+        if (this.field.disabled) return;
+
+        if (this.popup == null)
+        {
+            this.createPopup();
+
+        }
+        else
+        {
+            if (this.popup.visible())
+            {
+                this.hidePopup();
+                return;
+            }
+        }
+
+
+        var value = $F(this.field);
+
+        if (value == "")
+        {
+            this.datePicker.setDate(null);
+        }
+        else
+        {
+
+            // TODO: This is limited and americanized (not localized) to MM/DD/YYYY
+            var re = /^\s*(\d+)\/(\d+)\/(\d{2,4})\s*$/;
+            var matches = re.exec(value);
+
+
+            // If the RE is bad, raise the date picker anyway, showing
+            // the last valid date, or showing no date.
+
+            if (matches != null)
+            {
+
+                var month = Number(matches[1]);
+                var day = Number(matches[2])
+                var year = Number(matches[3]);
+
+            // For two digits, guestamate which century they want.
+
+                if (year < 100)
+                {
+                    if (year >= 60) year += 1900
+                    else year += 2000;
+                }
+
+                var date = new Date(value);
+
+                date.setMonth(month - 1);
+                date.setDate(day);
+                date.setFullYear(year);
+
+                this.datePicker.setDate(date);
+            }
+        }
+
+        this.positionPopup();
+
+        this.revealPopup();
+    },
+
+    createPopup : function()
+    {
+        this.datePicker = new DatePicker();
+
+        this.popup = this.datePicker.create().hide().absolutize();
+
+        this.field.insert({ after : this.popup });
+
+        this.datePicker.onselect = function()
+        {
+            this.field.value = this.formatDate(this.datePicker.getDate());
+
+            this.hidePopup();
+
+            new Effect.Highlight(this.field);
+
+        }.bind(this);
+    },
+
+    formatDate : function(date)
+    {
+        if (date == null) return "";
+
+        // TODO: This needs to localize; currently its Americanized (MM/DD/YYYY).
+        return (date.getMonth() + 1) + "/" + date.getDate() + "/" + date.getFullYear();
+    },
+
+    positionPopup : function()
+    {
+        var fieldPos = this.field.positionedOffset();
+
+        var height = this.field.getHeight();
+
+        this.popup.setStyle({ top: fieldPos.top + height + 2 + "px", left: fieldPos.left, width: "", height: "" });
+    },
+
+    hidePopup : function()
+    {
+
+        new Effect.Fade(this.popup, { duration: .20 });
+    },
+
+    revealPopup : function()
+    {
+
+        // Only show one DateField popup at a time.
+
+        if (Tapestry.DateField.activeDateField != undefined &&
+            Tapestry.DateField.activeDateField != this)
+        {
+            Tapestry.DateField.activeDateField.hidePopup();
+        }
+
+        new Effect.Appear(this.popup, { duration: .20 });
+
+        Tapestry.DateField.activeDateField = this;
+    }
+};
\ No newline at end of file

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/css/datepicker.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/css/datepicker.css?rev=620592&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/css/datepicker.css (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/css/datepicker.css Mon Feb 11 11:40:54 2008
@@ -0,0 +1,143 @@
+.datePicker {
+    border: 1px solid WindowText;
+    background: Window;
+    width: 170px;
+    padding: 0px;
+    cursor: default;
+    -moz-user-focus: normal;
+}
+
+.datePicker td {
+    font: smallcaption;
+    font: small-caption;
+    text-align: center;
+    color: WindowText;
+    cursor: default;
+    font-weight: normal !important;
+    -moz-user-select: none;
+    padding: 0;
+}
+
+.datePicker td.red {
+    color: red;
+}
+
+.datePicker .header {
+    background: ActiveCaption;
+    padding: 3px;
+    border-bottom: 1px solid WindowText;
+}
+
+.datePicker .headerTable {
+    width: 100%;
+}
+
+.datePicker .footer {
+    padding: 3px;
+}
+
+.datePicker .footerTable {
+    width: 100%;
+}
+
+.datePicker .grid {
+    padding: 3px;
+}
+
+.datePicker .gridTable {
+    width: 100%;
+}
+
+.datePicker .gridTable td {
+    width: 14.3%;
+}
+
+.datePicker .gridTable .daysRow td {
+    font-weight: bold !important;
+    border-bottom: 1px solid ThreeDDarkShadow;
+}
+
+.datePicker .grid .gridTable .upperLine {
+    width: 100%;
+    height: 2px;
+    overflow: hidden;
+    background: transparent;
+}
+
+.datePicker td.today {
+    font-weight: bold !important;
+}
+
+.datePicker td.selected {
+    background: Highlight;
+    color: HighlightText !important;
+}
+
+.datePicker td.labelContainer {
+    width: 100%;
+}
+
+.datePicker td .topLabel {
+    color: CaptionText;
+    display: block;
+    font-weight: bold !important;
+    width: 100%;
+    text-decoration: none;
+
+}
+
+.datePicker td.filler {
+    width: 100%;
+}
+
+.datePicker button {
+    border-width: 1px;
+    font: Caption;
+    font-weight: normal !important;
+    display: block;
+}
+
+.datePicker .previousButton {
+    background: buttonface url( "../images/arrow.left.png" ) no-repeat center center;
+}
+
+.datePicker .nextButton {
+    background: buttonface url( "../images/arrow.right.png" ) no-repeat center center;
+}
+
+.datePicker .previousButton,
+    .datePicker .nextButton {
+    width: 14px;
+    height: 14px;
+}
+
+.datePicker .todayButton,
+    .datePicker .noneButton {
+    width: 50px;
+}
+
+.datePicker .labelPopup {
+    position: absolute;
+    min-width: 130px;
+    background: Window;
+    border: 1px solid WindowText;
+    padding: 1px;
+}
+
+.datePicker .labelPopup a {
+    width: 100%;
+    display: block;
+    color: WindowText;
+    text-decoration: none;
+    white-space: nowrap;
+}
+
+.datePicker .labelPopup a:hover {
+    background: Highlight;
+    color: HighlightText;
+}
+
+.datePicker .labelPopup a.selected {
+    font-weight: bold;
+}
+

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/images/arrow.left.png
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/images/arrow.left.png?rev=620592&view=auto
==============================================================================
Binary file - no diff available.

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/images/arrow.left.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/images/arrow.right.png
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/images/arrow.right.png?rev=620592&view=auto
==============================================================================
Binary file - no diff available.

Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/images/arrow.right.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/js/datepicker.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/js/datepicker.js?rev=620592&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/js/datepicker.js (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/datepicker_106/js/datepicker.js Mon Feb 11 11:40:54 2008
@@ -0,0 +1,691 @@
+/*----------------------------------------------------------------------------\
+|                              Date Picker 1.06                               |
+|-----------------------------------------------------------------------------|
+|                         Created by Erik Arvidsson                           |
+|                  (http://webfx.eae.net/contact.html#erik)                   |
+|                      For WebFX (http://webfx.eae.net/)                      |
+|-----------------------------------------------------------------------------|
+|                            A DOM based Date Picker                          |
+|-----------------------------------------------------------------------------|
+|       Copyright (c) 1999, 2002, 2002, 2003, 2004, 2006 Erik Arvidsson       |
+|-----------------------------------------------------------------------------|
+| 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.                                                          |
+|-----------------------------------------------------------------------------|
+| Dependencies: datepicker.css      Date picker style declarations            |
+|-----------------------------------------------------------------------------|
+| 2002-02-10 | Changed _update method to only update the text nodes instead   |
+|            | rewriting the entire table. Also added support for mouse wheel |
+|            | in IE6.                                                        |
+| 2002-01-14 | Cleaned up for 1.0 public version                              |
+| 2002-01-15 | Replace all innerHTML calls with DOM1 methods                  |
+| 2002-01-18 | Minor IE6 bug that occured when dragging the mouse             |
+| 2002-01-19 | Added a popup that is shown when the user clicks on the month. |
+|            | This allows navigation to 6 adjacent months.                   |
+| 2002-04-10 | Fixed a bug that occured in the popup when a date was selected |
+|            | that caused surroundung months to "overflow"                   |
+|            | This had the effect that one could get two October months      |
+|            | listed.                                                        |
+| 2002-09-06 | I had missed one place were window was used instead of         |
+|            | doc.parentWindow                                               |
+| 2003-08-28 | Added support for ensurin no date overflow when changing       |
+|            | months.                                                        |
+| 2004-01-10 | Adding type on the buttons to ensure they are not submit       |
+|            | buttons. Minor CSS change for CSS2                             |
+| 2006-05-28 | Changed license to Apache Software License 2.0.                |
+|-----------------------------------------------------------------------------|
+| Created 2001-10-?? | All changes are in the log above. | Updated 2006-05-28 |
+\----------------------------------------------------------------------------*/
+
+// The DatePicker constructor
+// oDate : Date Optional argument representing the date to select
+// Note: some minor modifications for Tapestry, to work well as a popup.
+function DatePicker(oDate)
+{
+    // check arguments
+    if (arguments.length == 0)
+    {
+        this._selectedDate = new Date;
+        this._none = false;
+    }
+    else
+    {
+        this._selectedDate = oDate || new Date();
+        this._none = oDate == null;
+    }
+
+    this._matrix = [[],[],[],[],[],[],[]];
+    this._showNone = true;
+    this._showToday = true;
+    this._firstWeekDay = 0;	// start week with monday according to standards
+    this._redWeekDay = 6;	// sunday is the default red day.
+
+    this._dontChangeNone = false;
+}
+
+// two static fields describing the name of the months abd days
+DatePicker.months = [
+    "January", "February", "March", "April",
+    "May", "June", "July", "August",
+    "September", "October", "November", "December"];
+DatePicker.days = ["m", "t", "w", "t", "f", "s", "s"];
+
+
+// Function invoked whenever the selected date changes, whether by
+// navigation or when the user selects a date.
+DatePicker.prototype.onchange = function ()
+{
+};
+
+// onselect is more specified than onchange, and    is triggered only when the user makes a specific selection
+// using the calendar (rather than navigating to a new month). For Tapestry,
+// this will dismiss the popup.
+DatePicker.prototype.onselect = function()
+{
+}
+
+
+// create the nodes inside the date picker
+DatePicker.prototype.create = function (doc)
+{
+    if (doc == null) doc = document;
+
+    this._document = doc;
+
+	// create elements
+    this._el = doc.createElement("div");
+    this._el.className = "datePicker";
+
+	// header
+    var div = doc.createElement("div");
+    div.className = "header";
+    this._el.appendChild(div);
+
+    var headerTable = doc.createElement("table");
+    headerTable.className = "headerTable";
+    headerTable.cellSpacing = 0;
+    div.appendChild(headerTable);
+
+    var tBody = doc.createElement("tbody");
+    headerTable.appendChild(tBody);
+
+    var tr = doc.createElement("tr");
+    tBody.appendChild(tr);
+
+    var td = doc.createElement("td");
+    this._previousMonth = doc.createElement("button");
+    this._previousMonth.className = "previousButton";
+    this._previousMonth.setAttribute("type", "button");
+    td.appendChild(this._previousMonth);
+    tr.appendChild(td);
+
+    td = doc.createElement("td");
+    td.className = "labelContainer";
+    tr.appendChild(td);
+
+    this._topLabel = doc.createElement("a");
+    this._topLabel.className = "topLabel";
+    this._topLabel.href = "#";
+    this._topLabel.appendChild(doc.createTextNode(String.fromCharCode(160)));
+    td.appendChild(this._topLabel);
+
+    this._labelPopup = doc.createElement("div");
+    this._labelPopup.className = "labelPopup";
+	// no insertion
+
+    td = doc.createElement("td");
+    this._nextMonth = doc.createElement("button");
+    this._nextMonth.className = "nextButton";
+    this._nextMonth.setAttribute("type", "button");
+    td.appendChild(this._nextMonth);
+    tr.appendChild(td);
+
+	// grid
+    div = doc.createElement("div");
+    div.className = "grid";
+    this._el.appendChild(div);
+    this._table = div;
+
+	// footer
+    div = doc.createElement("div");
+    div.className = "footer";
+    this._el.appendChild(div);
+
+    var footerTable = doc.createElement("table");
+    footerTable.className = "footerTable";
+    footerTable.cellSpacing = 0;
+    div.appendChild(footerTable);
+
+    tBody = doc.createElement("tbody");
+    footerTable.appendChild(tBody);
+
+    tr = doc.createElement("tr");
+    tBody.appendChild(tr);
+
+    td = doc.createElement("td");
+    this._todayButton = doc.createElement("button");
+    this._todayButton.className = "todayButton";
+    this._todayButton.setAttribute("type", "button");
+    this._todayButton.appendChild(doc.createTextNode("Today"));
+    td.appendChild(this._todayButton);
+    tr.appendChild(td);
+
+    td = doc.createElement("td");
+    td.className = "filler";
+    td.appendChild(doc.createTextNode(String.fromCharCode(160)));
+    tr.appendChild(td);
+
+    td = doc.createElement("td");
+    this._noneButton = doc.createElement("button");
+    this._noneButton.className = "noneButton";
+    this._noneButton.setAttribute("type", "button");
+    this._noneButton.appendChild(doc.createTextNode("None"));
+    td.appendChild(this._noneButton);
+    tr.appendChild(td);
+
+
+    this._createTable(doc);
+
+    this._updateTable();
+    this._setTopLabel();
+
+    if (!this._showNone)
+        this._noneButton.style.visibility = "hidden";
+    if (!this._showToday)
+        this._todayButton.style.visibility = "hidden";
+
+	// IE55+ extension
+    this._previousMonth.hideFocus = true;
+    this._nextMonth.hideFocus = true;
+    this._todayButton.hideFocus = true;
+    this._noneButton.hideFocus = true;
+	// end IE55+ extension
+
+    // hook up events
+    var dp = this;
+	// buttons
+    this._previousMonth.onclick = function ()
+    {
+        dp._dontChangeNone = true;
+        dp.goToPreviousMonth();
+        dp._dontChangeNone = false;
+    };
+    this._nextMonth.onclick = function ()
+    {
+        dp._dontChangeNone = true;
+        dp.goToNextMonth();
+        dp._dontChangeNone = false;
+    };
+    this._todayButton.onclick = function ()
+    {
+        dp.goToToday();
+    };
+    this._noneButton.onclick = function ()
+    {
+        dp.setDate(null, true);
+    };
+
+    this._el.onselectstart = function ()
+    {
+        return false;
+    };
+
+    this._table.onclick = function (e)
+    {
+        // find event
+        if (e == null) e = doc.parentWindow.event;
+
+		// find td
+        var el = e.target != null ? e.target : e.srcElement;
+        while (el.nodeType != 1)
+            el = el.parentNode;
+        while (el != null && el.tagName && el.tagName.toLowerCase() != "td")
+            el = el.parentNode;
+
+		// if no td found, return
+        if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td")
+            return;
+
+        var d = new Date(dp._selectedDate);
+        var n = Number(el.firstChild.data);
+        if (isNaN(n) || n <= 0 || n == null)
+            return;
+
+        d.setDate(n);
+        dp.setDate(d, true);
+    };
+
+	// show popup
+    this._topLabel.onclick = function (e)
+    {
+        dp._showLabelPopup();
+        return false;
+    };
+
+    this._el.onkeydown = function (e)
+    {
+        if (e == null) e = doc.parentWindow.event;
+        var kc = e.keyCode != null ? e.keyCode : e.charCode;
+
+        if (kc < 37 || kc > 40) return true;
+
+        var d = new Date(dp._selectedDate).valueOf();
+        if (kc == 37) // left
+            d -= 24 * 60 * 60 * 1000;
+        else if (kc == 39) // right
+            d += 24 * 60 * 60 * 1000;
+        else if (kc == 38) // up
+            d -= 7 * 24 * 60 * 60 * 1000;
+        else if (kc == 40) // down
+            d += 7 * 24 * 60 * 60 * 1000;
+
+        dp.setDate(new Date(d), false);
+        return false;
+    }
+
+	// ie6 extension
+    this._el.onmousewheel = function (e)
+    {
+        if (e == null) e = doc.parentWindow.event;
+        var n = - e.wheelDelta / 120;
+        var d = new Date(dp._selectedDate);
+        var m = d.getMonth() + n;
+        d.setMonth(m);
+
+
+        dp._dontChangeNone = true;
+        dp.setDate(d, false);
+        dp._dontChangeNone = false;
+
+        return false;
+    }
+
+    return this._el;
+};
+
+DatePicker.prototype.setDate = function (oDate, isSelection)
+{
+
+    this._hideLabelPopup();
+
+	// if null then set None
+    if (oDate == null)
+    {
+        if (!this._none)
+        {
+            this._none = true;
+            this._setTopLabel();
+            this._updateTable();
+
+            if (typeof this.onchange == "function")
+                this.onchange();
+        }
+
+        if (isSelection)
+            this.onselect();
+
+        return;
+    }
+
+	// if string or number create a Date object
+    if (typeof oDate == "string" || typeof oDate == "number")
+    {
+        oDate = new Date(oDate);
+    }
+
+
+	// do not update if not really changed
+    if (this._selectedDate.getDate() != oDate.getDate() ||
+        this._selectedDate.getMonth() != oDate.getMonth() ||
+        this._selectedDate.getFullYear() != oDate.getFullYear() ||
+        this._none)
+    {
+
+        if (!this._dontChangeNone)
+            this._none = false;
+
+        this._selectedDate = new Date(oDate);
+
+        this._setTopLabel();
+        this._updateTable();
+
+        if (typeof this.onchange == "function")
+            this.onchange();
+
+        if (isSelection)
+            this.onselect();
+    }
+
+    if (!this._dontChangeNone)
+        this._none = false;
+
+}
+
+
+DatePicker.prototype.getDate = function ()
+{
+    if (this._none) return null;
+    return new Date(this._selectedDate);	// create a new instance
+}
+
+// creates the table elements and inserts them into the date picker
+DatePicker.prototype._createTable = function (doc)
+{
+    var str, i;
+    var rows = 6;
+    var cols = 7;
+    var currentWeek = 0;
+
+    var table = doc.createElement("table");
+    table.className = "gridTable";
+    table.cellSpacing = 0;
+
+    var tBody = doc.createElement("tbody");
+    table.appendChild(tBody);
+
+	// days row
+    var tr = doc.createElement("tr");
+    tr.className = "daysRow";
+
+    var td, tn;
+    var nbsp = String.fromCharCode(160);
+    for (i = 0; i < cols; i++)
+    {
+        td = doc.createElement("td");
+        td.appendChild(doc.createTextNode(nbsp));
+        tr.appendChild(td);
+    }
+    tBody.appendChild(tr);
+
+	// upper line
+    tr = doc.createElement("tr");
+    td = doc.createElement("td");
+    td.className = "upperLine";
+    td.colSpan = 7;
+    tr.appendChild(td);
+    tBody.appendChild(tr);
+
+	// rest
+    for (i = 0; i < rows; i++)
+    {
+        tr = doc.createElement("tr");
+        for (var j = 0; j < cols; j++)
+        {
+            td = doc.createElement("td");
+            td.appendChild(doc.createTextNode(nbsp));
+            tr.appendChild(td);
+        }
+        tBody.appendChild(tr);
+    }
+    str += "</table>";
+
+    if (this._table != null)
+        this._table.appendChild(table)
+};
+// this method updates all the text nodes inside the table as well
+// as all the classNames on the tds
+DatePicker.prototype._updateTable = function ()
+{
+    // if no element no need to continue
+    if (this._table == null) return;
+
+    var i;
+    var str = "";
+    var rows = 6;
+    var cols = 7;
+    var currentWeek = 0;
+
+    var cells = new Array(rows);
+    this._matrix = new Array(rows)
+    for (i = 0; i < rows; i++)
+    {
+        cells[i] = new Array(cols);
+        this._matrix[i] = new Array(cols);
+    }
+
+	// Set the tmpDate to this month
+    var tmpDate = new Date(this._selectedDate.getFullYear(),
+            this._selectedDate.getMonth(), 1);
+    var today = new Date();
+	// go thorugh all days this month and store the text
+    // and the class name in the cells matrix
+    for (i = 1; i < 32; i++)
+    {
+        tmpDate.setDate(i);
+		// convert to ISO, Monday is 0 and 6 is Sunday
+        var weekDay = ( tmpDate.getDay() + 6 ) % 7;
+        var colIndex = ( weekDay - this._firstWeekDay + 7 ) % 7;
+        if (tmpDate.getMonth() == this._selectedDate.getMonth())
+        {
+
+            var isToday = tmpDate.getDate() == today.getDate() &&
+                          tmpDate.getMonth() == today.getMonth() &&
+                          tmpDate.getFullYear() == today.getFullYear();
+
+            cells[currentWeek][colIndex] = { text: "", className: "" };
+
+            if (this._selectedDate.getDate() == tmpDate.getDate() && !this._none)
+                cells[currentWeek][colIndex].className += "selected ";
+            if (isToday)
+                cells[currentWeek][colIndex].className += "today ";
+            if (( tmpDate.getDay() + 6 ) % 7 == this._redWeekDay) // ISO
+                cells[currentWeek][colIndex].className += "red";
+
+            cells[currentWeek][colIndex].text =
+            this._matrix[currentWeek][colIndex] = tmpDate.getDate();
+
+            if (colIndex == 6)
+                currentWeek++;
+        }
+    }
+
+	// fix day letter order if not standard
+    var weekDays = DatePicker.days;
+    if (this._firstWeekDay != 0)
+    {
+        weekDays = new Array(7);
+        for (i = 0; i < 7; i++)
+            weekDays[i] = DatePicker.days[ (i + this._firstWeekDay) % 7];
+    }
+
+	// update text in days row
+    var tds = this._table.firstChild.tBodies[0].rows[0].cells;
+    for (i = 0; i < cols; i++)
+        tds[i].firstChild.data = weekDays[i];
+
+	// update the text nodes and class names
+    var trs = this._table.firstChild.tBodies[0].rows;
+    var tmpCell;
+    var nbsp = String.fromCharCode(160);
+    for (var y = 0; y < rows; y++)
+    {
+        for (var x = 0; x < cols; x++)
+        {
+            tmpCell = trs[y + 2].cells[x];
+            if (typeof cells[y][x] != "undefined")
+            {
+                tmpCell.className = cells[y][x].className;
+                tmpCell.firstChild.data = cells[y][x].text;
+            }
+            else
+            {
+                tmpCell.className = "";
+                tmpCell.firstChild.data = nbsp;
+            }
+        }
+    }
+}
+
+// sets the label showing the year and selected month
+DatePicker.prototype._setTopLabel = function ()
+{
+    var str = this._selectedDate.getFullYear() + " " + DatePicker.months[ this._selectedDate.getMonth() ];
+    if (this._topLabel != null)
+        this._topLabel.lastChild.data = str;
+}
+
+DatePicker.prototype.goToNextMonth = function ()
+{
+    var d = new Date(this._selectedDate);
+    d.setDate(Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() + 1,
+            d.getFullYear()))); // no need to catch dec -> jan for the year
+    d.setMonth(d.getMonth() + 1);
+    this.setDate(d);
+}
+
+DatePicker.prototype.goToPreviousMonth = function ()
+{
+    var d = new Date(this._selectedDate);
+    d.setDate(Math.min(d.getDate(), DatePicker.getDaysPerMonth(d.getMonth() - 1,
+            d.getFullYear()))); // no need to catch jan -> dec for the year
+    d.setMonth(d.getMonth() - 1);
+    this.setDate(d);
+}
+
+DatePicker.prototype.goToToday = function ()
+{
+    if (this._none)
+        // change the selectedDate to force update if none was true
+        this._selectedDate = new Date(this._selectedDate + 10000000000);
+    this._none = false;
+    this.setDate(new Date(), true);
+}
+
+DatePicker.prototype.setShowToday = function (bShowToday)
+{
+    if (typeof bShowToday == "string")
+        bShowToday = !/false|0|no/i.test(bShowToday);
+
+    if (this._todayButton != null)
+        this._todayButton.style.visibility = bShowToday ? "visible" : "hidden";
+    this._showToday = bShowToday;
+}
+
+DatePicker.prototype.getShowToday = function ()
+{
+    return this._showToday;
+}
+
+DatePicker.prototype.setShowNone = function (bShowNone)
+{
+    if (typeof bShowNone == "string")
+        bShowNone = !/false|0|no/i.test(bShowNone);
+
+    if (this._noneButton != null)
+        this._noneButton.style.visibility = bShowNone ? "visible" : "hidden";
+    this._showNone = bShowNone;
+}
+
+DatePicker.prototype.getShowNone = function ()
+{
+    return this._showNone;
+}
+
+// 0 is monday and 6 is sunday as in the ISO standard
+DatePicker.prototype.setFirstWeekDay = function (nFirstWeekDay)
+{
+    if (this._firstWeekDay != nFirstWeekDay)
+    {
+        this._firstWeekDay = nFirstWeekDay;
+        this._updateTable();
+    }
+}
+
+DatePicker.prototype.getFirstWeekDay = function ()
+{
+    return this._firstWeekDay;
+}
+
+// 0 is monday and 6 is sunday as in the ISO standard
+DatePicker.prototype.setRedWeekDay = function (nRedWeekDay)
+{
+    if (this._redWeekDay != nRedWeekDay)
+    {
+        this._redWeekDay = nRedWeekDay;
+        this._updateTable();
+    }
+}
+
+DatePicker.prototype.getRedWeekDay = function ()
+{
+    return this._redWeekDay;
+}
+
+
+DatePicker.prototype._showLabelPopup = function ()
+{
+
+    /*
+     this._labelPopup document.createElement( "DIV" );
+     div.className = "month-popup";
+     div.noWrap = true;
+     el.unselectable = div.unselectable = "on";
+     el.onselectstart = div.onselectstart = function () { return false; };
+     */
+
+    var dateContext = function (dp, d)
+    {
+        return function (e)
+        {
+            dp._dontChangeNone = true;
+            dp._hideLabelPopup();
+            dp.setDate(d);
+            dp._dontChangeNone = false;
+            return false;
+        };
+    };
+
+    var dp = this;
+
+	// clear all old elements in the popup
+    while (this._labelPopup.hasChildNodes())
+        this._labelPopup.removeChild(this._labelPopup.firstChild);
+
+    var a, tmp, tmp2;
+    for (var i = -3; i < 4; i++)
+    {
+        tmp = new Date(this._selectedDate);
+        tmp2 = new Date(this._selectedDate);	// need another tmp to catch year change when checking leap
+        tmp2.setDate(1);
+        tmp2.setMonth(tmp2.getMonth() + i);
+        tmp.setDate(Math.min(tmp.getDate(), DatePicker.getDaysPerMonth(tmp.getMonth() + i,
+                tmp2.getFullYear())));
+        tmp.setMonth(tmp.getMonth() + i);
+
+        a = this._document.createElement("a");
+        a.href = "javascript:void 0;";
+        a.onclick = dateContext(dp, tmp);
+        a.appendChild(this._document.createTextNode(tmp.getFullYear() + " " +
+                                                    DatePicker.months[ tmp.getMonth() ]));
+        if (i == 0)
+            a.className = "selected";
+        this._labelPopup.appendChild(a);
+    }
+
+    this._topLabel.parentNode.insertBefore(this._labelPopup, this._topLabel.parentNode.firstChild);
+};
+
+DatePicker.prototype._hideLabelPopup = function ()
+{
+    if (this._labelPopup.parentNode)
+        this._labelPopup.parentNode.removeChild(this._labelPopup);
+};
+
+DatePicker._daysPerMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
+DatePicker.getDaysPerMonth = function (nMonth, nYear)
+{
+    nMonth = (nMonth + 12) % 12;
+    var res = DatePicker._daysPerMonth[nMonth];
+    if (nMonth == 1)
+    {
+        res += nYear % 4 == 0 && !(nYear % 400 == 0) ? 1 : 0;
+    }
+    return res;
+};
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/default.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/default.css?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/default.css (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/default.css Mon Feb 11 11:40:54 2008
@@ -314,9 +314,9 @@
     clear: left;
 }
 
-BUTTON.t-calendar-trigger {
-    margin-left: 3px;
-    padding: none;
+IMG.t-calendar-trigger {
+    padding-left: 3px;
+    cursor: pointer;
 }
 
 DIV.t-autocomplete-menu UL {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js Mon Feb 11 11:40:54 2008
@@ -69,9 +69,7 @@
 
             if (form.firstError)
             {
-                field = $(field);
-                if (field.focus) field.focus();
-                if (field.select) field.select();
+                $(field).activate();
 
                 form.firstError = false;
             }
@@ -185,7 +183,7 @@
     // and its icon.
     decorateForValidationError : function (element, event, message)
     {
-        $(element).fieldEventManager.addDecorations(event, message);
+        $(element).fieldEventManager.addDecorations(message);
     }
 };
 
@@ -437,7 +435,7 @@
     // 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.
 
-    removeDecorations : function(event)
+    removeDecorations : function()
     {
         this.field.removeClassName("t-error");
 
@@ -455,7 +453,7 @@
     // event - the validation event
     // message - error message
 
-    addDecorations : function(event, message)
+    addDecorations : function(message)
     {
         this.field.addClassName("t-error");
 
@@ -514,7 +512,7 @@
         });
 
         if (! event.error)
-            this.removeDecorations(event);
+            this.removeDecorations();
     }
 };
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/logging.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/logging.apt?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/logging.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/logging.apt Mon Feb 11 11:40:54 2008
@@ -9,7 +9,7 @@
   
   The default configuration for logging uses 
   {{{http://logging.apache.org/log4j/}Log4J}} as the logging toolkit, though
-  {{{http://tapestry.apache.org/tapestry5/tapestry-ioc/logging.html}this can be changed}}.
+  {{{../../tapestry-ioc/logging.html}this can be changed}}.
   
   
 Class to Logger
@@ -117,7 +117,7 @@
   
 TRACE Level
 
-  At the TRACE level ''for pages'' enables extremely verbose logging of every activity that drives the rendering of output, such as each component
+  At the TRACE level <for pages> enables extremely verbose logging of every activity that drives the rendering of output, such as each component
   working its way through the {{{rendering.html}rendering stage machine}}.  Example:
   
 ----

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt Mon Feb 11 11:40:54 2008
@@ -287,7 +287,7 @@
   }
 +---+
 
-  The event handler has precendence over the translator.  Here it checks for the empty string
+  The event handler metohd has precendence over the translator.  Here it checks for the empty string
   (and note that the input may be null!) and evaluates that as zero.
 
   Again, returning null lets the normal translator do its work.
@@ -296,7 +296,7 @@
   {{{../../apidocs/org/apache/tapestry/ValidationException.html}ValidationException}} to indicate a value
   that can't be parsed.
 
-  Now, what if you want to perform your own custom validation?  That's another event: "validate":
+  Now, what if you want to perform your own custom validation?  That's another event: "validateInput":
 
 +---+
   void onValidateFromCount(Integer value) throws ValidationException

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt Mon Feb 11 11:40:54 2008
@@ -13,6 +13,9 @@
   Progress on Tapestry 5 is really taking off. This space lists some cool new features that have been added
   recently.
 
+  * Form components now trigger a "validateForm" event, not a "validate" event (so as to avoid conflict
+    with the "validate" event triggered by TextFields).
+
   * Tapestry now understands JDK 1.5 Generics, allowing for simple parameterized types for properties of data objects and components.
 
   * Tapestry now differentiates between development mode and production mode, primarily in how

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/DateFieldDemo.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/DateFieldDemo.tml?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/DateFieldDemo.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/DateFieldDemo.tml Mon Feb 11 11:40:54 2008
@@ -15,7 +15,7 @@
 
             <div class="t-beaneditor-row">
                 <t:label for="asteroidImpact"/>
-                <t:datefield t:id="asteroidImpact" editTime="true" format="%m/%d/%Y %H:%M"/>
+                <t:datefield t:id="asteroidImpact"/>
             </div>
 
 
@@ -33,7 +33,7 @@
         </p>
 
         <p>
-            Impact: [${asteroidImpactFormatted}]
+            Impact: [<t:output value="asteroidImpact" format="dateFormat"/>]
         </p>
     </t:if>
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/DateFieldTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/DateFieldTest.java?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/DateFieldTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/DateFieldTest.java Mon Feb 11 11:40:54 2008
@@ -14,74 +14,67 @@
 
 package org.apache.tapestry.corelib.components;
 
-import org.apache.tapestry.ComponentResources;
-import org.apache.tapestry.ioc.Location;
-import org.apache.tapestry.ioc.Messages;
-import org.apache.tapestry.ioc.internal.util.TapestryException;
 import org.apache.tapestry.test.TapestryTestCase;
-import org.testng.annotations.Test;
-
-import java.text.SimpleDateFormat;
 
 public class DateFieldTest extends TapestryTestCase
 {
 
-    @Test
-    public void convert_symbols_success() throws Exception
-    {
-        Messages messages = messagesFor(DateField.class);
-
-        DateField df = new DateField();
-        df.injectMessages(messages);
-
-        SimpleDateFormat format = df.toJavaDateFormat();
-
-        assertEquals(format.toPattern(), "MM/dd/yy");
-    }
-
-    @Test
-    public void convert_symbol_non_default() throws Exception
-    {
-        Messages messages = messagesFor(DateField.class);
-
-        DateField df = new DateField();
-        df.injectMessages(messages);
-        df.injectFormat("%d %b %Y");
-
-        SimpleDateFormat format = df.toJavaDateFormat();
-
-        assertEquals(format.toPattern(), "dd MMM yyyy");
-    }
-
-    @Test
-    public void unknown_symbol() throws Exception
-    {
-        Messages messages = messagesFor(DateField.class);
-        ComponentResources resources = mockComponentResources();
-        Location l = mockLocation();
-
-        train_getLocation(resources, l);
-
-        DateField df = new DateField();
-        df.injectMessages(messages);
-        df.injectFormat("%d %b %Z");
-        df.injectResources(resources);
-
-        replay();
-
-        try
-        {
-            df.toJavaDateFormat();
-            unreachable();
-        }
-        catch (TapestryException ex)
-        {
-            assertEquals(
-                    ex.getMessage(),
-                    "Unknown or unsupported symbol '%Z' (in format '%d %b %Z').");
-            assertSame(ex.getLocation(), l);
-        }
-
-        verify();
-    }
+//    @Test
+//    public void convert_symbols_success() throws Exception
+//    {
+//        Messages messages = messagesFor(DateField.class);
+//
+//        DateField df = new DateField();
+//        df.injectMessages(messages);
+//
+//        SimpleDateFormat format = df.toJavaDateFormat();
+//
+//        assertEquals(format.toPattern(), "MM/dd/yy");
+//    }
+
+//    @Test
+//    public void convert_symbol_non_default() throws Exception
+//    {
+//        Messages messages = messagesFor(DateField.class);
+//
+//        DateField df = new DateField();
+//        df.injectMessages(messages);
+//        df.injectFormat("%d %b %Y");
+//
+//        SimpleDateFormat format = df.toJavaDateFormat();
+//
+//        assertEquals(format.toPattern(), "dd MMM yyyy");
+//    }
+
+//    @Test
+//    public void unknown_symbol() throws Exception
+//    {
+//        Messages messages = messagesFor(DateField.class);
+//        ComponentResources resources = mockComponentResources();
+//        Location l = mockLocation();
+//
+//        train_getLocation(resources, l);
+//
+//        DateField df = new DateField();
+//        df.injectMessages(messages);
+//        df.injectFormat("%d %b %Z");
+//        df.injectResources(resources);
+//
+//        replay();
+//
+//        try
+//        {
+//            df.toJavaDateFormat();
+//            unreachable();
+//        }
+//        catch (TapestryException ex)
+//        {
+//            assertEquals(
+//                    ex.getMessage(),
+//                    "Unknown or unsupported symbol '%Z' (in format '%d %b %Z').");
+//            assertSame(ex.getLocation(), l);
+//        }
+//
+//        verify();
+//    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Mon Feb 11 11:40:54 2008
@@ -1138,15 +1138,15 @@
         start("DateField Demo");
 
         type("birthday", "12/24/66");
-        type("asteroidImpact", "05/28/2046 10:44");
+        type("asteroidImpact", "05/28/2046");
 
         clickAndWait(SUBMIT);
 
         assertTextPresent("Birthday: [12/24/1966]");
-        assertTextPresent("Impact: [05/28/2046 10:44]");
+        assertTextPresent("Impact: [05/28/2046]");
 
         assertFieldValue("birthday", "12/24/66");
-        assertFieldValue("asteroidImpact", "05/28/2046 10:44");
+        assertFieldValue("asteroidImpact", "05/28/46");
     }
 
     /**
@@ -1318,8 +1318,6 @@
                 "//input[@id='radio2']",
 
                 "//input[@id='datefield']",
-
-                "//button[@id='datefield:trigger']",
 
                 "//select[@id='palette:avail']",
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/DateFieldDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/DateFieldDemo.java?rev=620592&r1=620591&r2=620592&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/DateFieldDemo.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/DateFieldDemo.java Mon Feb 11 11:40:54 2008
@@ -55,9 +55,4 @@
     {
         _asteroidImpact = asteroidImpact;
     }
-
-    public String getAsteroidImpactFormatted()
-    {
-        return new SimpleDateFormat("MM/dd/yyyy hh:mm").format(_asteroidImpact);
-    }
 }