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 2012/08/14 03:33:15 UTC
[2/11] git commit: Remove FormEventManager,
replaced with top-level event handlers in the core/forms module
Remove the error icon image next to fields' Rebuild some of the logic linking
forms, fields, validators, and the FieldEventManager
Remove FormEventManager, replaced with top-level event handlers in the core/forms module
Remove the error icon image next to fields'
Rebuild some of the logic linking forms, fields, validators, and the FieldEventManager
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/b1c01eb8
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/b1c01eb8
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/b1c01eb8
Branch: refs/heads/5.4-js-rewrite
Commit: b1c01eb8a99ce25710caeda807ad1f5ae083648d
Parents: ce08b5a
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Mon Aug 13 18:32:39 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Mon Aug 13 18:32:39 2012 -0700
----------------------------------------------------------------------
.../META-INF/modules/core/events.coffee | 34 ++-
.../META-INF/modules/core/forms.coffee | 100 +++++
.../coffeescript/META-INF/modules/core/spi.coffee | 45 +++-
.../apache/tapestry5/corelib/components/Form.java | 26 +-
.../internal/DefaultValidationDecorator.java | 33 +--
.../services/ValidationDecoratorFactoryImpl.java | 10 +-
.../resources/org/apache/tapestry5/tapestry.js | 285 +++------------
.../internal/DefaultValidationDecoratorTest.java | 12 +-
8 files changed, 247 insertions(+), 298 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1c01eb8/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee
index 9832c02..b754fc8 100644
--- a/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/events.coffee
@@ -18,6 +18,34 @@
# trigger or listener for. Prototype requires that all custom events have a namespace prefix; jQuery appears to
# allow it without issue.
define
+ # Defines events related to the validation and submission of forms. See module `core/forms` for further details.
+ # All events are triggered on a specific HTML `<form>` element, and top-level handlers take it from there.
+ form:
+
+ # Triggered after `events.field.validate`, when there are no field validation exceptions, to allow for cross-form
+ # validation.
+ validateForm: "t5:form:validate"
+
+ # Triggered after `validateForm` (when there are no prior validation exceptions), to allow certain elements
+ # to configure themselves immediately before the form is submitted. This exists primarily for components such
+ # as FormFragment, which will update a enable or disable a hidden field to match the visibility of the fragment.
+ prepareForSubmit: "t5:form:prepare-for-submit"
+
+ # Triggered last, when the form is configured to not submit normally (as a standard POST). Under 5.3, this
+ # configuration was achieved by adding the `t-prevent-submission` CSS class; under 5.4 it is preferred to
+ # set the `data-t5-prevent-submission` attribute. In either case, the submit event is stopped, and this
+ # event fired to replace it; in most cases, a handler will then handle submitting the form's data as part
+ # of an Ajax request.
+ processSubmit: "t5:form:process-submit"
+
+ field:
+ # Triggered by the Form on all enclosed elements with the `data-t5-validation` attribute (indicating they are
+ # interested in participating with user input validation). The memo object passed to the event has an error property
+ # that can be set to true to indicate a validation error. Individual fields should determine if the field is in
+ # error and remove or add/update decorations for the validation error (decorations will transition from 5.3 style
+ # popups to Twitter Bootstrap in the near future).
+ validate: "t5:field:validate"
+
# Defines a number of event names specific to Tapestry Zones. Zones are Tapestry components that are structured
# to correctly support dynamic updates from the server via an Ajax request, and a standard response
# (the partial page render reponse). More details are available in the `core/zone` module.
@@ -26,11 +54,11 @@ define
# `core/spi:ElementWrapper`, or a string containing HTML markup). A standard top-level handler is defined by module
# `core/zone`, and is responsible for the actual update; it triggers the `events.zone.willUpdate` and
# `events.zone.didUpdate` events just before and just after changing the element's content.
- update: "t5:zone-update"
+ update: "t5:zone:update"
# Triggered (by the standard handler) just before the content in a Zone will be updated.
- willUpdate: "t5:zone-will-update"
+ willUpdate: "t5:zone:will-update"
# Triggered (by the standard hanndler) just after the content in a Zone has updated. If the zone was not visible, it
# is made visible after its content is changed, and before this event is triggered.
- didUpdate: "t5:zone-did-update"
\ No newline at end of file
+ didUpdate: "t5:zone:did-update"
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1c01eb8/tapestry-core/src/main/coffeescript/META-INF/modules/core/forms.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/forms.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/forms.coffee
new file mode 100644
index 0000000..452a4b0
--- /dev/null
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/forms.coffee
@@ -0,0 +1,100 @@
+# Copyright 2012 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.
+
+# ## core/forms
+#
+# Defines handlers for HTML forms and HTML field elements, specifically to control input validation.
+
+define ["core/events", "core/spi", "core/builder", "core/compat/tapestry"],
+ (events, spi, builder) ->
+
+ SKIP_VALIDATION = "data-t5-skip-validation"
+
+ isPreventSubmission = (element) ->
+ (element.hasClass Tapestry.PREVENT_SUBMISSION) or
+ (element.getAttribute "data-t5-prevent-submission")
+
+ clearSubmittingHidden = (form) ->
+ hidden = form.find "[name=t:submit]"
+
+ hidden.setValue null if hidden
+
+ return
+
+ setSubmittingHidden = (form, wrapper) ->
+ hidden = form.find "[name=t:submit]"
+
+ unless hidden
+ firstHidden = form.find "input[type=hidden]"
+ hidden = builder "input", type:"hidden", name:"t:submit"
+ firstHidden.insertBefore hidden
+
+ # TODO: Research why we need id and name and get rid of one if possible.
+ value = Object.toJSON [ wrapper.element.id, wrapper.element.name ]
+
+ hidden.setValue value
+
+ defaultValidateAndSubmit = (event) ->
+
+ if ((this.getAttribute "data-t5-validate") is "submit") and
+ (not this.getAttribute SKIP_VALIDATION)
+
+ this.removeAttribute SKIP_VALIDATION
+
+ memo = error: false
+
+ for field in this.findAll "[data-t5-validation]"
+ field.trigger events.field.validate, memo
+
+ # Only do form validation if all individual field validation
+ # was successful.
+ this.trigger events.form.validateForm, memo unless memo.error
+
+ if memo.error
+ clearSubmittingHidden this
+ event.stop()
+ return
+
+ # Allow certaint types of elements to do last-moment set up. Basically, this is for
+ # FormFragment, or similar, to make their t:hidden field enabled or disabled to match
+ # their UI's visible/hidden status. This is assumed to work.
+ this.trigger events.form.prepareForSubmit
+
+ # Sometimes we want to submit the form normally, for a full-page render.
+ # Othertimes we want to stop here and let the `events.form.processSubmit`
+ # handler take it from here.
+ if isPreventSubmission this
+ event.stop()
+ this.trigger events.form.processSubmit
+
+ # Otherwise, the event is good, there are no validation problems, let the normal processing commence.
+ return
+
+ spi.domReady ->
+ # TODO: May want to define a data attribute to control whether Tapestry gets
+ # involved at all?
+ spi.body().on "submit", "form", defaultValidateAndSubmit
+
+ # On any click on a submit or image, update the containing form to indicate that the element
+ # was responsible for the eventual submit; this is very important to Ajax updates, otherwise the
+ # information about which control triggered the submit gets lost.
+ spi.body().on "click", "input[type=submit], input[type=image]", (event) ->
+ setSubmittingHidden (spi.wrap this.element.form), this
+
+ exports =
+ setSubmittingElement: (form, element) ->
+ setSubmittingHidden form, element
+
+ skipValidation: (formWrapper) ->
+ form.wrapper setAttribute SKIP_VALIDATION, true
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1c01eb8/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee
index e85723d..9a52bad 100644
--- a/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/spi.coffee
@@ -20,9 +20,10 @@
# Prototype ... but does it in a way that makes it relatively easy to swap in jQuery instead.
define ["_", "prototype"], (_) ->
+ domLoaded = false
# When the document has loaded, convert `domReady` to just execute the callback immediately.
$(document).observe "dom:loaded", ->
- exports.domReady = (callback) -> callback()
+ domLoaded = true
# _internal_: splits the string into words separated by whitespace
split = (str) ->
@@ -198,6 +199,15 @@ define ["_", "prototype"], (_) ->
@element.writeAttribute name, value
this
+ # Removes the named attribute, if present.
+ #
+ # Returns this ElementWrapper
+ removeAttribute: (name) ->
+
+ @element.writeAttribute name, null
+ this
+
+
# Returns true if the element has the indicated class name, false otherwise.
hasClass: (name) ->
@element.hasClassName name
@@ -234,6 +244,14 @@ define ["_", "prototype"], (_) ->
@element.insert top: (convertContent content)
this
+ # Inserts new content (Element, ElementWrapper, or HTML markup string) into the DOM immediately before
+ # this ElementWrapper's element.
+ #
+ # Returns this ElementWrapper
+ insertBefore: (content) ->
+ @element.insert before: (convertContent content)
+ this
+
# Runs an animation to fade-in the element over the specified duration. The element may be hidden (via `hide()`)
# initially, and will be made visible (with initial opacity 0, which will increase over time) when the animation
# starts.
@@ -319,6 +337,21 @@ define ["_", "prototype"], (_) ->
this
+ # Returns the current value of the element (which must be a form control element, such as `<input>` or
+ # `<textarea>`).
+ # TODO: Define behavior for multi-named elements, such as `<select>`.
+
+ getValue: ->
+ @element.getValue()
+
+ # Updates the value for the element (whichmust be a form control element).
+ #
+ # Returns this ElementWrapper
+ setValue: (newValue) ->
+ @element.setValue newValue
+
+ this
+
# Adds an event handler for one or more events.
#
# events - one or more event names, separated by spaces
@@ -410,13 +443,18 @@ define ["_", "prototype"], (_) ->
# Invokes the callback only once the DOM has finished loading all elements (other resources, such as images, may
# still be in-transit). This is a safe time to search the DOM, modify attributes, and attach event handlers.
- # Returns this modules exports, for chained calls.
+ # Returns this modules exports, for chained calls. If the DOM has already loaded, the callback is invoked
+ # immediately.
domReady: (callback) ->
- $(document).observe "dom:loaded", callback
+ if domLoaded
+ callback()
+ else
+ $(document).observe "dom:loaded", callback
exports
# on() is used to add an event handler
+ #
# * selector - CSS selector used to select elements to attach handler to; alternately,
# a single DOM element, or an array of DOM elements
# * events - one or more event names, separated by spaces
@@ -424,6 +462,7 @@ define ["_", "prototype"], (_) ->
# * up to a selected element from an originating element that matches the CSS expression
# will invoke the handler.
# * handler - function invoked; the function is passed an Event object.
+ #
# Returns an EventHandler object, making it possible to turn event notifications on or off.
on: (selector, events, match, handler) ->
unless handler?
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1c01eb8/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
index 3d179dc..d8e0f4d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
@@ -34,11 +34,9 @@ import org.apache.tapestry5.ioc.services.PropertyAccess;
import org.apache.tapestry5.ioc.util.ExceptionUtils;
import org.apache.tapestry5.ioc.util.IdAllocator;
import org.apache.tapestry5.json.JSONArray;
-import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.runtime.Component;
import org.apache.tapestry5.services.*;
import org.apache.tapestry5.services.compatibility.DeprecationWarning;
-import org.apache.tapestry5.services.javascript.InitializationPriority;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
import org.slf4j.Logger;
@@ -204,9 +202,6 @@ public class Form implements ClientElement, FormValidationControl
@Environmental
private JavaScriptSupport javascriptSupport;
- @Environmental
- private JavaScriptSupport jsSupport;
-
@Inject
private Request request;
@@ -329,10 +324,10 @@ public class Form implements ClientElement, FormValidationControl
formSupport = createRenderTimeFormSupport(clientId, actionSink, allocator);
- addJavaScriptInitialization();
-
if (zone != null)
+ {
linkFormToZone(link);
+ }
environment.push(FormSupport.class, formSupport);
environment.push(ValidationTracker.class, tracker);
@@ -340,7 +335,7 @@ public class Form implements ClientElement, FormValidationControl
if (autofocus)
{
ValidationDecorator autofocusDecorator = new AutofocusValidationDecorator(
- environment.peek(ValidationDecorator.class), tracker, jsSupport);
+ environment.peek(ValidationDecorator.class), tracker, javascriptSupport);
environment.push(ValidationDecorator.class, autofocusDecorator);
}
@@ -365,6 +360,11 @@ public class Form implements ClientElement, FormValidationControl
writer.attributes("onsubmit", MarkupConstants.WAIT_FOR_PAGE);
}
+ if (clientValidation != ClientValidation.NONE)
+ {
+ writer.attributes("data-t5-validate", "submit");
+ }
+
resources.renderInformalParameters(writer);
div = writer.element("div", "class", CSSClassConstants.INVISIBLE);
@@ -382,16 +382,6 @@ public class Form implements ClientElement, FormValidationControl
environment.peek(Heartbeat.class).begin();
}
- private void addJavaScriptInitialization()
- {
- JSONObject validateSpec = new JSONObject()
- .put("submit", clientValidation != ClientValidation.NONE);
-
- JSONObject spec = new JSONObject("formId", clientId).put("validate", validateSpec);
-
- javascriptSupport.addInitializerCall(InitializationPriority.EARLY, "formEventManager", spec);
- }
-
@HeartbeatDeferred
private void linkFormToZone(Link link)
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1c01eb8/tapestry-core/src/main/java/org/apache/tapestry5/internal/DefaultValidationDecorator.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/DefaultValidationDecorator.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/DefaultValidationDecorator.java
index 6262334..5e2ce23 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/DefaultValidationDecorator.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/DefaultValidationDecorator.java
@@ -26,21 +26,16 @@ public final class DefaultValidationDecorator extends BaseValidationDecorator
{
private final Environment environment;
- private final Asset spacerAsset;
-
private final MarkupWriter markupWriter;
/**
* @param environment
- * used to locate objects and services during the render
- * @param spacerAsset
- * asset for a one-pixel spacer image used as a placeholder for the error marker icon
+ * used to locate objects and services during the render
* @param markupWriter
*/
- public DefaultValidationDecorator(Environment environment, Asset spacerAsset, MarkupWriter markupWriter)
+ public DefaultValidationDecorator(Environment environment, MarkupWriter markupWriter)
{
this.environment = environment;
- this.spacerAsset = spacerAsset;
this.markupWriter = markupWriter;
}
@@ -62,32 +57,14 @@ public final class DefaultValidationDecorator extends BaseValidationDecorator
}
/**
- * Writes an icon for field after the field. The icon has the same id as the field, with ":icon" appended. This is
- * expected by the default client-side JavaScript. The icon's src is a blank spacer image (this is to allow the
- * image displayed to be overridden via CSS). The icon's CSS class is "t-error-icon", with "t-invisible" added
- * if the field is not in error when rendered. If client validation is not enabled for the form containing the
- * field and the field is not in error, then the error icon itself is not rendered.
- *
+ * Does nothing; prior releases would write an error icon.
+ *
* @param field
- * which just completed rendering itself
+ * which just completed rendering itself
*/
@Override
public void afterField(Field field)
{
- boolean inError = inError(field);
-
- boolean clientValidationEnabled = getFormSupport().isClientValidationEnabled();
-
- if (inError || clientValidationEnabled)
- {
- String iconId = field.getClientId() + "_icon";
-
- String cssClass = inError ? "t-error-icon" : "t-error-icon t-invisible";
-
- markupWriter.element("img", "src", spacerAsset.toClientURL(), "alt", "", "class", cssClass, "id", iconId);
- markupWriter.end();
- }
-
}
private FormSupport getFormSupport()
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1c01eb8/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ValidationDecoratorFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ValidationDecoratorFactoryImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ValidationDecoratorFactoryImpl.java
index b7d0476..4385734 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ValidationDecoratorFactoryImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ValidationDecoratorFactoryImpl.java
@@ -14,10 +14,8 @@
package org.apache.tapestry5.internal.services;
-import org.apache.tapestry5.Asset;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.ValidationDecorator;
-import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.internal.DefaultValidationDecorator;
import org.apache.tapestry5.services.Environment;
import org.apache.tapestry5.services.ValidationDecoratorFactory;
@@ -26,17 +24,13 @@ public class ValidationDecoratorFactoryImpl implements ValidationDecoratorFactor
{
private final Environment environment;
- private final Asset spacerImage;
-
- public ValidationDecoratorFactoryImpl(Environment environment, @Path("${tapestry.spacer-image}")
- Asset spacerImage)
+ public ValidationDecoratorFactoryImpl(Environment environment)
{
this.environment = environment;
- this.spacerImage = spacerImage;
}
public ValidationDecorator newInstance(MarkupWriter writer)
{
- return new DefaultValidationDecorator(environment, spacerImage, writer);
+ return new DefaultValidationDecorator(environment, writer);
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1c01eb8/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js b/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
index af0a91a..92ee51c 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
@@ -18,10 +18,10 @@ define("core/compat/tapestry", [
"core/spi",
"core/events",
"core/ajax",
- "core/zone",
+ "core/forms",
"core/compat/t5-dom",
"core/compat/t5-console",
- "core/compat/t5-init"], function (_, spi, events, ajax) {
+ "core/compat/t5-init"], function (_, spi, events, ajax, forms) {
window.Tapestry = {
@@ -34,19 +34,19 @@ define("core/compat/tapestry", [
* of the Form's Tapestry object to true (which will prevent form
* submission).
*/
- FORM_VALIDATE_EVENT: "tapestry:formvalidate",
+ FORM_VALIDATE_EVENT: events.form.validate,
/**
* 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_PREPARE_FOR_SUBMIT_EVENT: events.form.prepareForSubmit,
/**
* Form event fired after prepare.
*/
- FORM_PROCESS_SUBMIT_EVENT: "tapestry:formprocesssubmit",
+ FORM_PROCESS_SUBMIT_EVENT: events.form.processSubmit,
/**
* Event, fired on a field element, to cause observers to validate the
@@ -63,7 +63,7 @@ define("core/compat/tapestry", [
* on all fields within the form (observed by each field's
* Tapestry.FieldEventManager).
*/
- FORM_VALIDATE_FIELDS_EVENT: "tapestry:validatefields",
+ FORM_VALIDATE_FIELDS_EVENT: events.field.validate,
/**
* Event, fired on the document object, which identifies the current focus
@@ -105,7 +105,10 @@ define("core/compat/tapestry", [
/**
* CSS Class added to a <form> element that directs Tapestry to
* prevent normal (HTTP POST) form submission, in favor of Ajax
- * (XmlHttpRequest) submission.
+ * (XmlHttpRequest) submission. This is still supported in Tapestry 5.4, but
+ * replaced with the data-t5-prevent-submission attribute.
+ *
+ * @deprecated Use data-t5-prevent-submission="true" instead
*/
PREVENT_SUBMISSION: "t-prevent-submission",
@@ -179,9 +182,7 @@ define("core/compat/tapestry", [
* such to load first. This simply observes the dom:loaded event on the
* document object (support for which is provided by Prototype).
*/
- onDOMLoaded: function (callback) {
- spi.domReady(callback);
- },
+ onDOMLoaded: spi.domReady,
/**
* Find all elements marked with the "t-invisible" CSS class and hide()s
@@ -225,26 +226,6 @@ define("core/compat/tapestry", [
t.observingFocusChange = true;
}
});
-
- /*
- * When a submit element is clicked, record the name of the element into
- * the associated form. This is necessary for some Ajax processing, see
- * TAPESTRY-2324.
- *
- * TAP5-1418: Added "type=image" so that they set the submitting element
- * correctly.
- */
- $$("INPUT[type=submit]", "INPUT[type=image]").each(function (element) {
- var t = $T(element);
-
- if (!t.trackingClicks) {
- element.observe("click", function () {
- $(element.form).setSubmittingElement(element);
- });
-
- t.trackingClicks = true;
- }
- });
},
/*
@@ -602,26 +583,6 @@ define("core/compat/tapestry", [
'FORM',
{
/**
- * Gets the Tapestry.FormEventManager for the form.
- *
- * @param form
- * form element
- */
- getFormEventManager: function (form) {
- form = $(form);
-
- var manager = $T(form).formEventManager;
-
- if (manager == undefined) {
-
- throw "No Tapestry.FormEventManager object has been created for form '#{id}'."
- .interpolate(form);
- }
-
- return manager;
- },
-
- /**
* Identifies in the form what is the cause of the
* submission. The element's id is stored into the t:submit
* hidden field (created as needed).
@@ -633,8 +594,7 @@ define("core/compat/tapestry", [
* (a Submit or LinkSubmit)
*/
setSubmittingElement: function (form, element) {
- form.getFormEventManager()
- .setSubmittingElement(element);
+ forms.setSubmittingControl(spi.wrap(form), spi.wrap(element));
},
/**
@@ -642,7 +602,7 @@ define("core/compat/tapestry", [
* the form.
*/
skipValidation: function (form) {
- $T(form).skipValidation = true;
+ forms.skipValidation(spi.wrap(form));
},
/**
@@ -768,6 +728,7 @@ define("core/compat/tapestry", [
* function to be passed the field value
*/
addValidator: function (element, validator) {
+
element.observe(Tapestry.FIELD_VALIDATE_EVENT, function (event) {
try {
validator.call(this, event.memo.translated);
@@ -989,20 +950,6 @@ define("core/compat/tapestry", [
},
/**
- * Sets up a Tapestry.FormEventManager for the form, and enables
- * events for validations. This is executed with
- * InitializationPriority.EARLY, to ensure that the FormEventManager
- * exists vefore any validations are added for fields within the
- * Form.
- *
- * @since 5.2.2
- */
- formEventManager: function (spec) {
- $T(spec.formId).formEventManager = new Tapestry.FormEventManager(
- spec);
- },
-
- /**
* Keys in the masterSpec are ids of field control elements. Value
* is a list of validation specs. Each validation spec is a 2 or 3
* element array.
@@ -1073,7 +1020,7 @@ define("core/compat/tapestry", [
*/
$(clientId).observeAction("click", function (event) {
$(this.form).skipValidation();
- $(this.form).setSubmittingElement(clientId);
+ $(this.form).setSubmittingElement($(clientId));
$(this.form).performSubmit(event);
});
}
@@ -1091,7 +1038,7 @@ define("core/compat/tapestry", [
required: function (field, message) {
$(field).getFieldEventManager().requiredCheck = function (value) {
- if ((T5._.isString(value) && value.strip() == '')
+ if ((_.isString(value) && value.strip() == '')
|| value == null)
$(field).showValidationMessage(message);
};
@@ -1265,7 +1212,6 @@ define("core/compat/tapestry", [
return;
if (Prototype.Browser.IE) {
- var _ = T5._;
this.outerDiv.show();
@@ -1311,7 +1257,7 @@ define("core/compat/tapestry", [
var div = this.outerDiv;
- T5._.delay(function () {
+ _.delay(function () {
div.hide();
}, this.IE_FADE_TIME);
@@ -1335,138 +1281,31 @@ define("core/compat/tapestry", [
}
});
- Tapestry.FormEventManager = Class.create({
-
- initialize: function (spec) {
- this.form = $(spec.formId);
- this.validateOnSubmit = spec.validate.submit;
-
- this.form.onsubmit = this.handleSubmit.bindAsEventListener(this);
- },
-
- /**
- * Identifies in the form what is the cause of the submission. The element's
- * id is stored into the t:submit hidden field (created as needed).
- *
- * @param element
- * id or element that is the cause of the submit (a Submit or
- * LinkSubmit)
- */
- setSubmittingElement: function (element) {
-
- if (!this.submitHidden) {
- // skip if this is not a tapestry controlled form
- if (this.form.getInputs("hidden", "t:formdata").size() == 0)
- return;
-
- var hiddens = this.form.getInputs("hidden", "t:submit");
-
- if (hiddens.size() == 0) {
-
- /**
- * Create a new hidden field directly after the first hidden
- * field in the form.
- */
- var firstHidden = this.form.getInputs("hidden").first();
-
- this.submitHidden = new Element("input", {
- type: "hidden",
- name: "t:submit"
- });
-
- firstHidden.insert({
- after: this.submitHidden
- });
- } else
- this.submitHidden = hiddens.first();
- }
-
- this.submitHidden.value = element == null ? null : Object.toJSON([$(element).id, $(element).name]);
- },
-
- handleSubmit: function (domevent) {
-
- /*
- * Necessary because we set the onsubmit property of the form, rather
- * than observing the event. But that's because we want to specfically
- * overwrite any other handlers.
- */
- Event.extend(domevent);
-
- var t = $T(this.form);
-
- t.validationError = false;
-
- if (!t.skipValidation) {
-
- t.skipValidation = false;
-
- /* Let all the fields do their validations first. */
-
- this.form.fire(Tapestry.FORM_VALIDATE_FIELDS_EVENT, this.form);
-
- /*
- * 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). Still trying
- * to figure out what should get focus from this kind of event.
- */
- if (!t.validationError)
- this.form.fire(Tapestry.FORM_VALIDATE_EVENT, this.form);
-
- if (t.validationError) {
- domevent.stop();
-
- /*
- * Because the submission failed, the last submit element is
- * cleared, since the form may be submitted for some other
- * reason later.
- */
- this.setSubmittingElement(null);
-
- return false;
- }
- }
-
- 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 run
- * via Ajax.Request.
- */
-
- if (this.form.hasClassName(Tapestry.PREVENT_SUBMISSION)) {
- domevent.stop();
+ Tapestry.FieldEventManager = Class.create({
- /*
- * Instead fire the event (a listener will then trigger the Ajax
- * submission). This is really a hook for the ZoneManager.
- */
- this.form.fire(Tapestry.FORM_PROCESS_SUBMIT_EVENT);
+ initialize: function (field) {
- return false;
- }
+ this.field = $(field);
- /* Validation is OK, not doing Ajax, continue as planned. */
+ this.translator = Prototype.K;
- return true;
- }
- });
+ // This marker clues in the Form that validation should be triggered on this
+ // element.
+ this.field.writeAttribute("data-t5-validation", true);
- Tapestry.FieldEventManager = Class.create({
+ var _this = this;
- initialize: function (field) {
- this.field = $(field);
+ $(this.field).observe(Tapestry.FORM_VALIDATE_FIELDS_EVENT,
+ function (event) {
- this.translator = Prototype.K;
+ _this.validateInput();
- var fem = $(this.field.form).getFormEventManager();
+ if (_this.inError()) {
+ event.memo.error = true;
- if (fem.validateOnSubmit) {
- $(this.field.form).observe(Tapestry.FORM_VALIDATE_FIELDS_EVENT,
- this.validateInput.bindAsEventListener(this));
- }
+ }
+ }
+ );
},
getLabel: function () {
@@ -1479,11 +1318,7 @@ define("core/compat/tapestry", [
},
getIcon: function () {
- if (!this.icon) {
- this.icon = $(this.field.id + "_icon");
- }
-
- return this.icon;
+ return null;
},
/**
@@ -1495,8 +1330,6 @@ define("core/compat/tapestry", [
this.getLabel() && this.getLabel().removeClassName("t-error");
- this.getIcon() && this.getIcon().hide();
-
if (this.errorPopup)
this.errorPopup.hide();
},
@@ -1510,75 +1343,63 @@ define("core/compat/tapestry", [
* validation message to display
*/
showValidationMessage: function (message) {
- $T(this.field).validationError = true;
- $T(this.field.form).validationError = true;
this.field.addClassName("t-error");
this.getLabel() && this.getLabel().addClassName("t-error");
- var icon = this.getIcon();
-
- if (icon && !icon.visible()) {
- new Effect.Appear(this.icon);
- }
-
if (this.errorPopup == undefined)
this.errorPopup = new Tapestry.ErrorPopup(this.field);
this.errorPopup.showMessage(message);
},
+ inError: function () {
+ return this.field.hasClassName("t-error");
+ },
+
/**
- * 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
+ * Invoked when a form is submitted to perform
+ * field validations. Field validations are skipped for disabled fields or fields that are not visible.
+ * 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 () {
+ this.removeDecorations();
+
if (this.field.disabled)
- return false;
+ return;
if (!this.field.isDeepVisible())
- return false;
-
- var t = $T(this.field);
+ return;
var value = $F(this.field);
- t.validationError = false;
-
- if (this.requiredCheck)
+ if (this.requiredCheck) {
this.requiredCheck.call(this, value);
+ if (this.inError()) { return; }
+ }
+
/*
* Don't try to validate blank values; if the field is required, that
* error is already noted and presented to the user.
*/
-
- if (!t.validationError && !(T5._.isString(value) && value.blank())) {
+ if (!(_.isString(value) && value.blank())) {
var translated = this.translator(value);
/*
* If Format went ok, perhaps do the other validations.
*/
- if (!t.validationError) {
+ if (!this.inError()) {
this.field.fire(Tapestry.FIELD_VALIDATE_EVENT, {
value: value,
- translated: translated
+ translated: translated,
});
}
- }
- /* Lastly, if no validation errors were found, remove the decorations. */
-
- if (!t.validationError)
- this.field.removeDecorations();
-
- return t.validationError;
+ }
}
});
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1c01eb8/tapestry-core/src/test/java/org/apache/tapestry5/internal/DefaultValidationDecoratorTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/DefaultValidationDecoratorTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/DefaultValidationDecoratorTest.java
index aa10245..c3cf7cf 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/DefaultValidationDecoratorTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/DefaultValidationDecoratorTest.java
@@ -34,7 +34,7 @@ public class DefaultValidationDecoratorTest extends TapestryTestCase
replay();
- ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+ ValidationDecorator decorator = new DefaultValidationDecorator(env, null);
decorator.insideLabel(null, null);
@@ -56,7 +56,7 @@ public class DefaultValidationDecoratorTest extends TapestryTestCase
Element e = writer.element("label", "accesskey", "f");
- ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+ ValidationDecorator decorator = new DefaultValidationDecorator(env, null);
decorator.insideLabel(field, e);
@@ -82,7 +82,7 @@ public class DefaultValidationDecoratorTest extends TapestryTestCase
Element e = writer.element("label", "accesskey", "f", "class", "foo");
- ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+ ValidationDecorator decorator = new DefaultValidationDecorator(env, null);
decorator.insideLabel(field, e);
@@ -107,7 +107,7 @@ public class DefaultValidationDecoratorTest extends TapestryTestCase
writer.element("input", "type", "text", "name", "ex", "class", "foo", "value", "freddy", "size", "30");
- ValidationDecorator decorator = new DefaultValidationDecorator(env, null, writer);
+ ValidationDecorator decorator = new DefaultValidationDecorator(env, writer);
decorator.insideField(field);
@@ -129,7 +129,7 @@ public class DefaultValidationDecoratorTest extends TapestryTestCase
replay();
- ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+ ValidationDecorator decorator = new DefaultValidationDecorator(env, null);
decorator.insideField(field);
@@ -148,7 +148,7 @@ public class DefaultValidationDecoratorTest extends TapestryTestCase
replay();
- ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+ ValidationDecorator decorator = new DefaultValidationDecorator(env, null);
decorator.insideLabel(field, null);