You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by iv...@apache.org on 2013/11/09 07:49:11 UTC

git commit: WICKET-5411 auto label auto update during ajax

Updated Branches:
  refs/heads/wicket-6.x 4e9a83fdc -> a73209bea


WICKET-5411 auto label auto update during ajax


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/a73209be
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/a73209be
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/a73209be

Branch: refs/heads/wicket-6.x
Commit: a73209beab8814a06f2e085384ad87bdf1fda212
Parents: 4e9a83f
Author: Igor Vaynberg <ig...@gmail.com>
Authored: Fri Nov 8 22:48:22 2013 -0800
Committer: Igor Vaynberg <ig...@gmail.com>
Committed: Fri Nov 8 22:48:22 2013 -0800

----------------------------------------------------------------------
 .../form/AjaxFormComponentUpdatingBehavior.java |   2 +-
 .../wicket/core/util/string/CssUtils.java       |  14 ++
 .../markup/html/form/AutoLabelResolver.java     | 130 ++++++++++++++++++-
 .../apache/wicket/markup/html/form/Form.java    |  24 +++-
 .../wicket/markup/html/form/FormComponent.java  |  34 ++++-
 .../wicket/protocol/http/WebApplication.java    |  36 +++--
 6 files changed, 212 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
index 7eab478..bd8267c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
@@ -160,8 +160,8 @@ public abstract class AjaxFormComponentUpdatingBehavior extends AjaxEventBehavio
 		catch (RuntimeException e)
 		{
 			onError(target, e);
-
 		}
+		formComponent.updateAutoLabels(target);
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java b/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
index a4944a3..7de8669 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
@@ -103,4 +103,18 @@ public final class CssUtils
 		}
 		response.write(" />");
 	}
+	
+	/**
+	 * Get a standardized key for a CSS class.
+	 * 
+	 * @param scope
+	 *            scope of CSS class
+	 * @param facet
+	 *            facet of CSS class
+	 * @return CSS key
+	 */
+	public static String key(Class<?> scope, String facet)
+	{
+		return scope.getSimpleName() + ".CSS." + facet;
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
index 562e6ed..7892fa7 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
@@ -16,9 +16,14 @@
  */
 package org.apache.wicket.markup.html.form;
 
+import java.io.Serializable;
+
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.MetaDataKey;
 import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.core.util.string.CssUtils;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.MarkupStream;
 import org.apache.wicket.markup.html.TransparentWebMarkupContainer;
@@ -36,11 +41,14 @@ import org.slf4j.LoggerFactory;
  * <li>Outputs the {@code for} attribute with the value equivalent to the markup id of the
  * referenced form component</li>
  * <li>Appends {@code required} css class to the {@code <label>} tag if the referenced form
- * component is required</li>
+ * component is required. Name of the css class can be overwritten by having a i18n property defined
+ * for key AutoLabelResolver.CSS.required</li>
  * <li>Appends {@code error} css class to the {@code <label>} tag if the referenced form component
- * has failed validation</li>
+ * has failed validation. Name of the css class can be overwritten by having a i18n property defined
+ * for key AutoLabelResolver.CSS.error</li>
  * <li>Appends {@code disabled} css class to the {@code <label>} tag if the referenced form
- * component has is not enabled in hierarchy</li>
+ * component has is not enabled in hierarchy. Name of the css class can be overwritten by having a i18n property defined
+ * for key AutoLabelResolver.CSS.disabled</li>
  * </ul>
  * 
  * <p>
@@ -64,6 +72,14 @@ public class AutoLabelResolver implements IComponentResolver
 
 	static final String WICKET_FOR = ":for";
 
+	public static final String CSS_REQUIRED_KEY = CssUtils.key(AutoLabelResolver.class, "requried");
+	public static final String CSS_DISABLED_KEY = CssUtils.key(AutoLabelResolver.class, "requried");
+	public static final String CSS_ERROR_KEY = CssUtils.key(AutoLabelResolver.class, "requried");
+	private static final String CSS_DISABLED_DEFAULT = "disabled";
+	private static final String CSS_REQUIRED_DEFAULT = "required";
+	private static final String CSS_ERROR_DEFAULT = "error";
+
+
 	@Override
 	public Component resolve(final MarkupContainer container, final MarkupStream markupStream,
 		final ComponentTag tag)
@@ -99,6 +115,11 @@ public class AutoLabelResolver implements IComponentResolver
 			}
 		}
 
+		if (component instanceof FormComponent)
+		{
+			component.setMetaData(MARKER_KEY, new AutoLabelMarker((FormComponent<?>)component));
+		}
+
 		return new AutoLabel("label" + container.getPage().getAutoIndex(), component);
 	}
 
@@ -161,6 +182,100 @@ public class AutoLabelResolver implements IComponentResolver
 		return null;
 	}
 
+	public static final String getLabelIdFor(Component component)
+	{
+		return component.getMarkupId() + "-w-lbl";
+	}
+
+	public static final MetaDataKey<AutoLabelMarker> MARKER_KEY = new MetaDataKey<AutoLabelMarker>()
+	{
+	};
+
+	/**
+	 * Marker used to track whether or not a form component has an associated auto label by its mere
+	 * presense as well as some attributes of the component across requests.
+	 * 
+	 * @author igor
+	 * 
+	 */
+	public static final class AutoLabelMarker implements Serializable
+	{
+		public static final short VALID = 0x01;
+		public static final short REQUIRED = 0x02;
+		public static final short ENABLED = 0x04;
+
+		private short flags;
+
+		public AutoLabelMarker(FormComponent<?> component)
+		{
+			setFlag(VALID, component.isValid());
+			setFlag(REQUIRED, component.isRequired());
+			setFlag(ENABLED, component.isEnabledInHierarchy());
+		}
+
+		public void updateFrom(FormComponent<?> component, AjaxRequestTarget target)
+		{
+			boolean valid = component.isValid(), required = component.isRequired(), enabled = component.isEnabledInHierarchy();
+
+			if (isValid() != valid)
+			{
+				target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
+					getLabelIdFor(component), component.getString(CSS_ERROR_KEY, null, CSS_ERROR_DEFAULT),
+					!valid));
+			}
+
+			if (isRequired() != required)
+			{
+				target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
+					getLabelIdFor(component), component.getString(CSS_REQUIRED_KEY, null, CSS_REQUIRED_DEFAULT),
+					required));
+			}
+
+			if (isEnabled() != enabled)
+			{
+				target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
+					getLabelIdFor(component), component.getString(CSS_DISABLED_KEY, null, CSS_DISABLED_DEFAULT),
+					!enabled));
+			}
+
+			setFlag(VALID, valid);
+			setFlag(REQUIRED, required);
+			setFlag(ENABLED, enabled);
+		}
+
+		public boolean isValid()
+		{
+			return getFlag(VALID);
+		}
+
+		public boolean isEnabled()
+		{
+			return getFlag(ENABLED);
+		}
+
+		public boolean isRequired()
+		{
+			return getFlag(REQUIRED);
+		}
+
+		private boolean getFlag(final int flag)
+		{
+			return (flags & flag) != 0;
+		}
+
+		private void setFlag(final short flag, final boolean set)
+		{
+			if (set)
+			{
+				flags |= flag;
+			}
+			else
+			{
+				flags &= ~flag;
+			}
+		}
+	}
+
 	/**
 	 * Component that is attached to the {@code <label>} tag and takes care of writing out the label
 	 * text as well as setting classes on the {@code <label>} tag
@@ -184,23 +299,24 @@ public class AutoLabelResolver implements IComponentResolver
 		{
 			super.onComponentTag(tag);
 			tag.put("for", component.getMarkupId());
+			tag.put("id", getLabelIdFor(component));
 
 			if (component instanceof FormComponent)
 			{
 				FormComponent<?> fc = (FormComponent<?>)component;
 				if (fc.isRequired())
 				{
-					tag.append("class", "required", " ");
+					tag.append("class", component.getString(CSS_REQUIRED_KEY, null, CSS_REQUIRED_DEFAULT), " ");
 				}
 				if (!fc.isValid())
 				{
-					tag.append("class", "error", " ");
+					tag.append("class", component.getString(CSS_ERROR_KEY, null, CSS_ERROR_DEFAULT), " ");
 				}
 			}
 
 			if (!component.isEnabledInHierarchy())
 			{
-				tag.append("class", "disabled", " ");
+				tag.append("class", component.getString(CSS_DISABLED_KEY, null, CSS_DISABLED_DEFAULT), " ");
 			}
 		}
 
@@ -213,4 +329,6 @@ public class AutoLabelResolver implements IComponentResolver
 			return component;
 		}
 	}
+
+
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
index a7f07f3..a9ea6a6 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
@@ -30,6 +30,7 @@ import org.apache.wicket.Component;
 import org.apache.wicket.IGenericComponent;
 import org.apache.wicket.Page;
 import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.MarkupStream;
@@ -144,10 +145,8 @@ import org.slf4j.LoggerFactory;
  * @param <T>
  *            The model object type
  */
-public class Form<T> extends WebMarkupContainer
-	implements
-		IFormSubmitListener,
-		IGenericComponent<T>
+public class Form<T> extends WebMarkupContainer implements IFormSubmitListener,
+	IGenericComponent<T>
 {
 	private static final String HIDDEN_DIV_START = "<div style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">";
 
@@ -778,6 +777,20 @@ public class Form<T> extends WebMarkupContainer
 		{
 			callOnError(submitter);
 		}
+
+
+		if (((WebRequest)getRequest()).isAjax())
+		{
+			final AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class);
+			visitChildren(FormComponent.class, new IVisitor<FormComponent<?>, Void>()
+			{
+				@Override
+				public void component(FormComponent<?> component, IVisit<Void> visit)
+				{
+					component.updateAutoLabels(target);
+				}
+			});
+		}
 	}
 
 	/**
@@ -2089,7 +2102,8 @@ public class Form<T> extends WebMarkupContainer
 	 * 
 	 * @author igor
 	 */
-	public static enum MethodMismatchResponse {
+	public static enum MethodMismatchResponse
+	{
 		/**
 		 * Continue processing.
 		 */

http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
index 450b6bd..e4b89ed 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
@@ -36,12 +36,15 @@ import org.apache.wicket.IConverterLocator;
 import org.apache.wicket.IGenericComponent;
 import org.apache.wicket.Localizer;
 import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.core.util.lang.WicketObjects;
 import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.form.AutoLabelResolver.AutoLabelMarker;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.IPropertyReflectionAwareModel;
 import org.apache.wicket.model.Model;
+import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.util.convert.ConversionException;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.lang.Args;
@@ -98,11 +101,8 @@ import org.slf4j.LoggerFactory;
  *            The model object type
  * 
  */
-public abstract class FormComponent<T> extends LabeledWebMarkupContainer
-	implements
-		IFormVisitorParticipant,
-		IFormModelUpdateListener,
-		IGenericComponent<T>
+public abstract class FormComponent<T> extends LabeledWebMarkupContainer implements
+	IFormVisitorParticipant, IFormModelUpdateListener, IGenericComponent<T>
 {
 	private static final Logger logger = LoggerFactory.getLogger(FormComponent.class);
 
@@ -1579,6 +1579,30 @@ public abstract class FormComponent<T> extends LabeledWebMarkupContainer
 	}
 
 	/**
+	 * Updates auto label css classes such as error/required during ajax updates when the labels may
+	 * not be directly repainted in the response.
+	 * 
+	 * @param target
+	 */
+	public final void updateAutoLabels(AjaxRequestTarget target)
+	{
+		if (!((WebApplication)getApplication()).getUpdateAutoLabelsOnAjaxRequests())
+		{
+			return;
+		}
+
+		AutoLabelMarker marker = getMetaData(AutoLabelResolver.MARKER_KEY);
+	
+		if (marker == null)
+		{
+			// this component does not have an auto label
+			return;
+		}
+
+		marker.updateFrom(this, target);
+	}
+
+	/**
 	 * Update the model of a {@link FormComponent} containing a {@link Collection}.
 	 * 
 	 * If the model object does not yet exists, a new {@link ArrayList} is filled with the converted

http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
index ba69791..22bbfda 100644
--- a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
+++ b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
@@ -394,10 +394,10 @@ public abstract class WebApplication extends Application
 	/**
 	 * Registers a replacement resource for the given javascript resource. This replacement can be
 	 * another {@link JavaScriptResourceReference} for a packaged resource, but it can also be an
-	 * {@link org.apache.wicket.request.resource.UrlResourceReference} to replace the resource by a resource hosted on a CDN.
-	 * Registering a replacement will cause the resource to replaced by the given resource
-	 * throughout the application: if {@code base} is added, {@code replacement} will be added
-	 * instead.
+	 * {@link org.apache.wicket.request.resource.UrlResourceReference} to replace the resource by a
+	 * resource hosted on a CDN. Registering a replacement will cause the resource to replaced by
+	 * the given resource throughout the application: if {@code base} is added, {@code replacement}
+	 * will be added instead.
 	 * 
 	 * @param base
 	 *            The resource to replace
@@ -415,10 +415,10 @@ public abstract class WebApplication extends Application
 	/**
 	 * Registers a replacement resource for the given CSS resource. This replacement can be another
 	 * {@link CssResourceReference} for a packaged resource, but it can also be an
-	 * {@link org.apache.wicket.request.resource.UrlResourceReference} to replace the resource by a resource hosted on a CDN.
-	 * Registering a replacement will cause the resource to replaced by the given resource
-	 * throughout the application: if {@code base} is added, {@code replacement} will be added
-	 * instead.
+	 * {@link org.apache.wicket.request.resource.UrlResourceReference} to replace the resource by a
+	 * resource hosted on a CDN. Registering a replacement will cause the resource to replaced by
+	 * the given resource throughout the application: if {@code base} is added, {@code replacement}
+	 * will be added instead.
 	 * 
 	 * @param base
 	 *            The resource to replace
@@ -951,9 +951,8 @@ public abstract class WebApplication extends Application
 		return ajaxRequestTargetListeners;
 	}
 
-	private static class DefaultAjaxRequestTargetProvider
-		implements
-			IContextProvider<AjaxRequestTarget, Page>
+	private static class DefaultAjaxRequestTargetProvider implements
+		IContextProvider<AjaxRequestTarget, Page>
 	{
 		@Override
 		public AjaxRequestTarget get(Page page)
@@ -981,4 +980,19 @@ public abstract class WebApplication extends Application
 		}
 		return filterFactoryManager;
 	}
+
+	/**
+	 * If true, auto label css classes such as {@code error} and {@code required} will be updated
+	 * after form component processing during an ajax request. This allows auto labels to correctly
+	 * reflect the state of the form component even if they are not part of the ajax markup update.
+	 * 
+	 * TODO in wicket-7 this should move into a settings object. cannot move in 6.x because it
+	 * requires a change to a setting interface.
+	 * 
+	 * @return {@code true} iff enabled
+	 */
+	public boolean getUpdateAutoLabelsOnAjaxRequests()
+	{
+		return true;
+	}
 }


Re: git commit: WICKET-5411 auto label auto update during ajax

Posted by Martin Grigorov <mg...@apache.org>.
I am not aware of any other impl but having such JS bits in the Java code
would make it hard for any such attempt in the future.

For example jQuery#extend is Wicket#bind.
I suggest to have Wicket.Dom.toggleClass.
I will redo it soon unless there are objections.

On Sun, Nov 10, 2013 at 1:43 AM, Igor Vaynberg <ig...@gmail.com>wrote:

> i suppose that bit of js can be rewritten to use pure dom, but has
> anyone actually ever implemented wicket-event.js and wicket-ajax.js
> using anything other then jquery?
>
> -igor
>
> On Sat, Nov 9, 2013 at 1:34 PM, Martin Grigorov <mg...@apache.org>
> wrote:
> > On Sat, Nov 9, 2013 at 8:49 AM, <iv...@apache.org> wrote:
> >
> >> Updated Branches:
> >>   refs/heads/wicket-6.x 4e9a83fdc -> a73209bea
> >>
> >>
> >> WICKET-5411 auto label auto update during ajax
> >>
> >>
> >> Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
> >> Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/a73209be
> >> Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/a73209be
> >> Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/a73209be
> >>
> >> Branch: refs/heads/wicket-6.x
> >> Commit: a73209beab8814a06f2e085384ad87bdf1fda212
> >> Parents: 4e9a83f
> >> Author: Igor Vaynberg <ig...@gmail.com>
> >> Authored: Fri Nov 8 22:48:22 2013 -0800
> >> Committer: Igor Vaynberg <ig...@gmail.com>
> >> Committed: Fri Nov 8 22:48:22 2013 -0800
> >>
> >> ----------------------------------------------------------------------
> >>  .../form/AjaxFormComponentUpdatingBehavior.java |   2 +-
> >>  .../wicket/core/util/string/CssUtils.java       |  14 ++
> >>  .../markup/html/form/AutoLabelResolver.java     | 130
> ++++++++++++++++++-
> >>  .../apache/wicket/markup/html/form/Form.java    |  24 +++-
> >>  .../wicket/markup/html/form/FormComponent.java  |  34 ++++-
> >>  .../wicket/protocol/http/WebApplication.java    |  36 +++--
> >>  6 files changed, 212 insertions(+), 28 deletions(-)
> >> ----------------------------------------------------------------------
> >>
> >>
> >>
> >>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> >> ----------------------------------------------------------------------
> >> diff --git
> >>
> a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> >>
> b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> >> index 7eab478..bd8267c 100644
> >> ---
> >>
> a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> >> +++
> >>
> b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> >> @@ -160,8 +160,8 @@ public abstract class
> >> AjaxFormComponentUpdatingBehavior extends AjaxEventBehavio
> >>                 catch (RuntimeException e)
> >>                 {
> >>                         onError(target, e);
> >> -
> >>                 }
> >> +               formComponent.updateAutoLabels(target);
> >>         }
> >>
> >>         /**
> >>
> >>
> >>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> >> ----------------------------------------------------------------------
> >> diff --git
> >>
> a/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> >>
> b/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> >> index a4944a3..7de8669 100644
> >> ---
> >>
> a/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> >> +++
> >>
> b/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> >> @@ -103,4 +103,18 @@ public final class CssUtils
> >>                 }
> >>                 response.write(" />");
> >>         }
> >> +
> >> +       /**
> >> +        * Get a standardized key for a CSS class.
> >> +        *
> >> +        * @param scope
> >> +        *            scope of CSS class
> >> +        * @param facet
> >> +        *            facet of CSS class
> >> +        * @return CSS key
> >> +        */
> >> +       public static String key(Class<?> scope, String facet)
> >> +       {
> >> +               return scope.getSimpleName() + ".CSS." + facet;
> >> +       }
> >>  }
> >>
> >>
> >>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> >> ----------------------------------------------------------------------
> >> diff --git
> >>
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> >>
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> >> index 562e6ed..7892fa7 100644
> >> ---
> >>
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> >> +++
> >>
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> >> @@ -16,9 +16,14 @@
> >>   */
> >>  package org.apache.wicket.markup.html.form;
> >>
> >> +import java.io.Serializable;
> >> +
> >>  import org.apache.wicket.Component;
> >>  import org.apache.wicket.MarkupContainer;
> >> +import org.apache.wicket.MetaDataKey;
> >>  import org.apache.wicket.WicketRuntimeException;
> >> +import org.apache.wicket.ajax.AjaxRequestTarget;
> >> +import org.apache.wicket.core.util.string.CssUtils;
> >>  import org.apache.wicket.markup.ComponentTag;
> >>  import org.apache.wicket.markup.MarkupStream;
> >>  import org.apache.wicket.markup.html.TransparentWebMarkupContainer;
> >> @@ -36,11 +41,14 @@ import org.slf4j.LoggerFactory;
> >>   * <li>Outputs the {@code for} attribute with the value equivalent to
> the
> >> markup id of the
> >>   * referenced form component</li>
> >>   * <li>Appends {@code required} css class to the {@code <label>} tag if
> >> the referenced form
> >> - * component is required</li>
> >> + * component is required. Name of the css class can be overwritten by
> >> having a i18n property defined
> >> + * for key AutoLabelResolver.CSS.required</li>
> >>   * <li>Appends {@code error} css class to the {@code <label>} tag if
> the
> >> referenced form component
> >> - * has failed validation</li>
> >> + * has failed validation. Name of the css class can be overwritten by
> >> having a i18n property defined
> >> + * for key AutoLabelResolver.CSS.error</li>
> >>   * <li>Appends {@code disabled} css class to the {@code <label>} tag if
> >> the referenced form
> >> - * component has is not enabled in hierarchy</li>
> >> + * component has is not enabled in hierarchy. Name of the css class can
> >> be overwritten by having a i18n property defined
> >> + * for key AutoLabelResolver.CSS.disabled</li>
> >>   * </ul>
> >>   *
> >>   * <p>
> >> @@ -64,6 +72,14 @@ public class AutoLabelResolver implements
> >> IComponentResolver
> >>
> >>         static final String WICKET_FOR = ":for";
> >>
> >> +       public static final String CSS_REQUIRED_KEY =
> >> CssUtils.key(AutoLabelResolver.class, "requried");
> >> +       public static final String CSS_DISABLED_KEY =
> >> CssUtils.key(AutoLabelResolver.class, "requried");
> >> +       public static final String CSS_ERROR_KEY =
> >> CssUtils.key(AutoLabelResolver.class, "requried");
> >> +       private static final String CSS_DISABLED_DEFAULT = "disabled";
> >> +       private static final String CSS_REQUIRED_DEFAULT = "required";
> >> +       private static final String CSS_ERROR_DEFAULT = "error";
> >> +
> >> +
> >>         @Override
> >>         public Component resolve(final MarkupContainer container, final
> >> MarkupStream markupStream,
> >>                 final ComponentTag tag)
> >> @@ -99,6 +115,11 @@ public class AutoLabelResolver implements
> >> IComponentResolver
> >>                         }
> >>                 }
> >>
> >> +               if (component instanceof FormComponent)
> >> +               {
> >> +                       component.setMetaData(MARKER_KEY, new
> >> AutoLabelMarker((FormComponent<?>)component));
> >> +               }
> >> +
> >>                 return new AutoLabel("label" +
> >> container.getPage().getAutoIndex(), component);
> >>         }
> >>
> >> @@ -161,6 +182,100 @@ public class AutoLabelResolver implements
> >> IComponentResolver
> >>                 return null;
> >>         }
> >>
> >> +       public static final String getLabelIdFor(Component component)
> >> +       {
> >> +               return component.getMarkupId() + "-w-lbl";
> >> +       }
> >> +
> >> +       public static final MetaDataKey<AutoLabelMarker> MARKER_KEY =
> new
> >> MetaDataKey<AutoLabelMarker>()
> >> +       {
> >> +       };
> >> +
> >> +       /**
> >> +        * Marker used to track whether or not a form component has an
> >> associated auto label by its mere
> >> +        * presense as well as some attributes of the component across
> >> requests.
> >> +        *
> >> +        * @author igor
> >> +        *
> >> +        */
> >> +       public static final class AutoLabelMarker implements
> Serializable
> >> +       {
> >> +               public static final short VALID = 0x01;
> >> +               public static final short REQUIRED = 0x02;
> >> +               public static final short ENABLED = 0x04;
> >> +
> >> +               private short flags;
> >> +
> >> +               public AutoLabelMarker(FormComponent<?> component)
> >> +               {
> >> +                       setFlag(VALID, component.isValid());
> >> +                       setFlag(REQUIRED, component.isRequired());
> >> +                       setFlag(ENABLED,
> component.isEnabledInHierarchy());
> >> +               }
> >> +
> >> +               public void updateFrom(FormComponent<?> component,
> >> AjaxRequestTarget target)
> >> +               {
> >> +                       boolean valid = component.isValid(), required =
> >> component.isRequired(), enabled = component.isEnabledInHierarchy();
> >> +
> >> +                       if (isValid() != valid)
> >> +                       {
> >> +
> >> target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
> >>
> >
> > Until now we haven't used jQuery APIs directly in the Java code.
> > This makes it harder to use different impl of wicket-event/ajax js.
> >
> >
> >> +                                       getLabelIdFor(component),
> >> component.getString(CSS_ERROR_KEY, null, CSS_ERROR_DEFAULT),
> >> +                                       !valid));
> >> +                       }
> >> +
> >> +                       if (isRequired() != required)
> >> +                       {
> >> +
> >> target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
> >> +                                       getLabelIdFor(component),
> >> component.getString(CSS_REQUIRED_KEY, null, CSS_REQUIRED_DEFAULT),
> >> +                                       required));
> >> +                       }
> >> +
> >> +                       if (isEnabled() != enabled)
> >> +                       {
> >> +
> >> target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
> >> +                                       getLabelIdFor(component),
> >> component.getString(CSS_DISABLED_KEY, null, CSS_DISABLED_DEFAULT),
> >> +                                       !enabled));
> >> +                       }
> >> +
> >> +                       setFlag(VALID, valid);
> >> +                       setFlag(REQUIRED, required);
> >> +                       setFlag(ENABLED, enabled);
> >> +               }
> >> +
> >> +               public boolean isValid()
> >> +               {
> >> +                       return getFlag(VALID);
> >> +               }
> >> +
> >> +               public boolean isEnabled()
> >> +               {
> >> +                       return getFlag(ENABLED);
> >> +               }
> >> +
> >> +               public boolean isRequired()
> >> +               {
> >> +                       return getFlag(REQUIRED);
> >> +               }
> >> +
> >> +               private boolean getFlag(final int flag)
> >> +               {
> >> +                       return (flags & flag) != 0;
> >> +               }
> >> +
> >> +               private void setFlag(final short flag, final boolean
> set)
> >> +               {
> >> +                       if (set)
> >> +                       {
> >> +                               flags |= flag;
> >> +                       }
> >> +                       else
> >> +                       {
> >> +                               flags &= ~flag;
> >> +                       }
> >> +               }
> >> +       }
> >> +
> >>         /**
> >>          * Component that is attached to the {@code <label>} tag and
> takes
> >> care of writing out the label
> >>          * text as well as setting classes on the {@code <label>} tag
> >> @@ -184,23 +299,24 @@ public class AutoLabelResolver implements
> >> IComponentResolver
> >>                 {
> >>                         super.onComponentTag(tag);
> >>                         tag.put("for", component.getMarkupId());
> >> +                       tag.put("id", getLabelIdFor(component));
> >>
> >>                         if (component instanceof FormComponent)
> >>                         {
> >>                                 FormComponent<?> fc =
> >> (FormComponent<?>)component;
> >>                                 if (fc.isRequired())
> >>                                 {
> >> -                                       tag.append("class", "required",
> "
> >> ");
> >> +                                       tag.append("class",
> >> component.getString(CSS_REQUIRED_KEY, null, CSS_REQUIRED_DEFAULT), " ");
> >>                                 }
> >>                                 if (!fc.isValid())
> >>                                 {
> >> -                                       tag.append("class", "error", "
> ");
> >> +                                       tag.append("class",
> >> component.getString(CSS_ERROR_KEY, null, CSS_ERROR_DEFAULT), " ");
> >>                                 }
> >>                         }
> >>
> >>                         if (!component.isEnabledInHierarchy())
> >>                         {
> >> -                               tag.append("class", "disabled", " ");
> >> +                               tag.append("class",
> >> component.getString(CSS_DISABLED_KEY, null, CSS_DISABLED_DEFAULT), " ");
> >>                         }
> >>                 }
> >>
> >> @@ -213,4 +329,6 @@ public class AutoLabelResolver implements
> >> IComponentResolver
> >>                         return component;
> >>                 }
> >>         }
> >> +
> >> +
> >>  }
> >>
> >>
> >>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> >> ----------------------------------------------------------------------
> >> diff --git
> >> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> >> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> >> index a7f07f3..a9ea6a6 100644
> >> ---
> >> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> >> +++
> >> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> >> @@ -30,6 +30,7 @@ import org.apache.wicket.Component;
> >>  import org.apache.wicket.IGenericComponent;
> >>  import org.apache.wicket.Page;
> >>  import org.apache.wicket.WicketRuntimeException;
> >> +import org.apache.wicket.ajax.AjaxRequestTarget;
> >>  import org.apache.wicket.behavior.Behavior;
> >>  import org.apache.wicket.markup.ComponentTag;
> >>  import org.apache.wicket.markup.MarkupStream;
> >> @@ -144,10 +145,8 @@ import org.slf4j.LoggerFactory;
> >>   * @param <T>
> >>   *            The model object type
> >>   */
> >> -public class Form<T> extends WebMarkupContainer
> >> -       implements
> >> -               IFormSubmitListener,
> >> -               IGenericComponent<T>
> >> +public class Form<T> extends WebMarkupContainer implements
> >> IFormSubmitListener,
> >> +       IGenericComponent<T>
> >>  {
> >>         private static final String HIDDEN_DIV_START = "<div
> >>
> style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">";
> >>
> >> @@ -778,6 +777,20 @@ public class Form<T> extends WebMarkupContainer
> >>                 {
> >>                         callOnError(submitter);
> >>                 }
> >> +
> >> +
> >> +               if (((WebRequest)getRequest()).isAjax())
> >> +               {
> >> +                       final AjaxRequestTarget target =
> >> getRequestCycle().find(AjaxRequestTarget.class);
> >> +                       visitChildren(FormComponent.class, new
> >> IVisitor<FormComponent<?>, Void>()
> >> +                       {
> >> +                               @Override
> >> +                               public void component(FormComponent<?>
> >> component, IVisit<Void> visit)
> >> +                               {
> >> +
> component.updateAutoLabels(target);
> >> +                               }
> >> +                       });
> >> +               }
> >>         }
> >>
> >>         /**
> >> @@ -2089,7 +2102,8 @@ public class Form<T> extends WebMarkupContainer
> >>          *
> >>          * @author igor
> >>          */
> >> -       public static enum MethodMismatchResponse {
> >> +       public static enum MethodMismatchResponse
> >> +       {
> >>                 /**
> >>                  * Continue processing.
> >>                  */
> >>
> >>
> >>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> >> ----------------------------------------------------------------------
> >> diff --git
> >>
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> >>
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> >> index 450b6bd..e4b89ed 100644
> >> ---
> >>
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> >> +++
> >>
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> >> @@ -36,12 +36,15 @@ import org.apache.wicket.IConverterLocator;
> >>  import org.apache.wicket.IGenericComponent;
> >>  import org.apache.wicket.Localizer;
> >>  import org.apache.wicket.WicketRuntimeException;
> >> +import org.apache.wicket.ajax.AjaxRequestTarget;
> >>  import org.apache.wicket.behavior.Behavior;
> >>  import org.apache.wicket.core.util.lang.WicketObjects;
> >>  import org.apache.wicket.markup.ComponentTag;
> >> +import
> >> org.apache.wicket.markup.html.form.AutoLabelResolver.AutoLabelMarker;
> >>  import org.apache.wicket.model.IModel;
> >>  import org.apache.wicket.model.IPropertyReflectionAwareModel;
> >>  import org.apache.wicket.model.Model;
> >> +import org.apache.wicket.protocol.http.WebApplication;
> >>  import org.apache.wicket.util.convert.ConversionException;
> >>  import org.apache.wicket.util.convert.IConverter;
> >>  import org.apache.wicket.util.lang.Args;
> >> @@ -98,11 +101,8 @@ import org.slf4j.LoggerFactory;
> >>   *            The model object type
> >>   *
> >>   */
> >> -public abstract class FormComponent<T> extends
> LabeledWebMarkupContainer
> >> -       implements
> >> -               IFormVisitorParticipant,
> >> -               IFormModelUpdateListener,
> >> -               IGenericComponent<T>
> >> +public abstract class FormComponent<T> extends
> LabeledWebMarkupContainer
> >> implements
> >> +       IFormVisitorParticipant, IFormModelUpdateListener,
> >> IGenericComponent<T>
> >>  {
> >>         private static final Logger logger =
> >> LoggerFactory.getLogger(FormComponent.class);
> >>
> >> @@ -1579,6 +1579,30 @@ public abstract class FormComponent<T> extends
> >> LabeledWebMarkupContainer
> >>         }
> >>
> >>         /**
> >> +        * Updates auto label css classes such as error/required during
> >> ajax updates when the labels may
> >> +        * not be directly repainted in the response.
> >> +        *
> >> +        * @param target
> >> +        */
> >> +       public final void updateAutoLabels(AjaxRequestTarget target)
> >> +       {
> >> +               if
> >>
> (!((WebApplication)getApplication()).getUpdateAutoLabelsOnAjaxRequests())
> >> +               {
> >> +                       return;
> >> +               }
> >> +
> >> +               AutoLabelMarker marker =
> >> getMetaData(AutoLabelResolver.MARKER_KEY);
> >> +
> >> +               if (marker == null)
> >> +               {
> >> +                       // this component does not have an auto label
> >> +                       return;
> >> +               }
> >> +
> >> +               marker.updateFrom(this, target);
> >> +       }
> >> +
> >> +       /**
> >>          * Update the model of a {@link FormComponent} containing a
> {@link
> >> Collection}.
> >>          *
> >>          * If the model object does not yet exists, a new {@link
> >> ArrayList} is filled with the converted
> >>
> >>
> >>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> >> ----------------------------------------------------------------------
> >> diff --git
> >>
> a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> >>
> b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> >> index ba69791..22bbfda 100644
> >> ---
> >>
> a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> >> +++
> >>
> b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> >> @@ -394,10 +394,10 @@ public abstract class WebApplication extends
> >> Application
> >>         /**
> >>          * Registers a replacement resource for the given javascript
> >> resource. This replacement can be
> >>          * another {@link JavaScriptResourceReference} for a packaged
> >> resource, but it can also be an
> >> -        * {@link
> org.apache.wicket.request.resource.UrlResourceReference}
> >> to replace the resource by a resource hosted on a CDN.
> >> -        * Registering a replacement will cause the resource to replaced
> >> by the given resource
> >> -        * throughout the application: if {@code base} is added, {@code
> >> replacement} will be added
> >> -        * instead.
> >> +        * {@link
> org.apache.wicket.request.resource.UrlResourceReference}
> >> to replace the resource by a
> >> +        * resource hosted on a CDN. Registering a replacement will
> cause
> >> the resource to replaced by
> >> +        * the given resource throughout the application: if {@code
> base}
> >> is added, {@code replacement}
> >> +        * will be added instead.
> >>          *
> >>          * @param base
> >>          *            The resource to replace
> >> @@ -415,10 +415,10 @@ public abstract class WebApplication extends
> >> Application
> >>         /**
> >>          * Registers a replacement resource for the given CSS resource.
> >> This replacement can be another
> >>          * {@link CssResourceReference} for a packaged resource, but it
> >> can also be an
> >> -        * {@link
> org.apache.wicket.request.resource.UrlResourceReference}
> >> to replace the resource by a resource hosted on a CDN.
> >> -        * Registering a replacement will cause the resource to replaced
> >> by the given resource
> >> -        * throughout the application: if {@code base} is added, {@code
> >> replacement} will be added
> >> -        * instead.
> >> +        * {@link
> org.apache.wicket.request.resource.UrlResourceReference}
> >> to replace the resource by a
> >> +        * resource hosted on a CDN. Registering a replacement will
> cause
> >> the resource to replaced by
> >> +        * the given resource throughout the application: if {@code
> base}
> >> is added, {@code replacement}
> >> +        * will be added instead.
> >>          *
> >>          * @param base
> >>          *            The resource to replace
> >> @@ -951,9 +951,8 @@ public abstract class WebApplication extends
> >> Application
> >>                 return ajaxRequestTargetListeners;
> >>         }
> >>
> >> -       private static class DefaultAjaxRequestTargetProvider
> >> -               implements
> >> -                       IContextProvider<AjaxRequestTarget, Page>
> >> +       private static class DefaultAjaxRequestTargetProvider implements
> >> +               IContextProvider<AjaxRequestTarget, Page>
> >>         {
> >>                 @Override
> >>                 public AjaxRequestTarget get(Page page)
> >> @@ -981,4 +980,19 @@ public abstract class WebApplication extends
> >> Application
> >>                 }
> >>                 return filterFactoryManager;
> >>         }
> >> +
> >> +       /**
> >> +        * If true, auto label css classes such as {@code error} and
> >> {@code required} will be updated
> >> +        * after form component processing during an ajax request. This
> >> allows auto labels to correctly
> >> +        * reflect the state of the form component even if they are not
> >> part of the ajax markup update.
> >> +        *
> >> +        * TODO in wicket-7 this should move into a settings object.
> >> cannot move in 6.x because it
> >> +        * requires a change to a setting interface.
> >> +        *
> >> +        * @return {@code true} iff enabled
> >> +        */
> >> +       public boolean getUpdateAutoLabelsOnAjaxRequests()
> >> +       {
> >> +               return true;
> >> +       }
> >>  }
> >>
> >>
>

Re: git commit: WICKET-5411 auto label auto update during ajax

Posted by Igor Vaynberg <ig...@gmail.com>.
i suppose that bit of js can be rewritten to use pure dom, but has
anyone actually ever implemented wicket-event.js and wicket-ajax.js
using anything other then jquery?

-igor

On Sat, Nov 9, 2013 at 1:34 PM, Martin Grigorov <mg...@apache.org> wrote:
> On Sat, Nov 9, 2013 at 8:49 AM, <iv...@apache.org> wrote:
>
>> Updated Branches:
>>   refs/heads/wicket-6.x 4e9a83fdc -> a73209bea
>>
>>
>> WICKET-5411 auto label auto update during ajax
>>
>>
>> Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
>> Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/a73209be
>> Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/a73209be
>> Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/a73209be
>>
>> Branch: refs/heads/wicket-6.x
>> Commit: a73209beab8814a06f2e085384ad87bdf1fda212
>> Parents: 4e9a83f
>> Author: Igor Vaynberg <ig...@gmail.com>
>> Authored: Fri Nov 8 22:48:22 2013 -0800
>> Committer: Igor Vaynberg <ig...@gmail.com>
>> Committed: Fri Nov 8 22:48:22 2013 -0800
>>
>> ----------------------------------------------------------------------
>>  .../form/AjaxFormComponentUpdatingBehavior.java |   2 +-
>>  .../wicket/core/util/string/CssUtils.java       |  14 ++
>>  .../markup/html/form/AutoLabelResolver.java     | 130 ++++++++++++++++++-
>>  .../apache/wicket/markup/html/form/Form.java    |  24 +++-
>>  .../wicket/markup/html/form/FormComponent.java  |  34 ++++-
>>  .../wicket/protocol/http/WebApplication.java    |  36 +++--
>>  6 files changed, 212 insertions(+), 28 deletions(-)
>> ----------------------------------------------------------------------
>>
>>
>>
>> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
>> b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
>> index 7eab478..bd8267c 100644
>> ---
>> a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
>> +++
>> b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
>> @@ -160,8 +160,8 @@ public abstract class
>> AjaxFormComponentUpdatingBehavior extends AjaxEventBehavio
>>                 catch (RuntimeException e)
>>                 {
>>                         onError(target, e);
>> -
>>                 }
>> +               formComponent.updateAutoLabels(target);
>>         }
>>
>>         /**
>>
>>
>> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
>> b/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
>> index a4944a3..7de8669 100644
>> ---
>> a/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
>> +++
>> b/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
>> @@ -103,4 +103,18 @@ public final class CssUtils
>>                 }
>>                 response.write(" />");
>>         }
>> +
>> +       /**
>> +        * Get a standardized key for a CSS class.
>> +        *
>> +        * @param scope
>> +        *            scope of CSS class
>> +        * @param facet
>> +        *            facet of CSS class
>> +        * @return CSS key
>> +        */
>> +       public static String key(Class<?> scope, String facet)
>> +       {
>> +               return scope.getSimpleName() + ".CSS." + facet;
>> +       }
>>  }
>>
>>
>> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
>> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
>> index 562e6ed..7892fa7 100644
>> ---
>> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
>> +++
>> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
>> @@ -16,9 +16,14 @@
>>   */
>>  package org.apache.wicket.markup.html.form;
>>
>> +import java.io.Serializable;
>> +
>>  import org.apache.wicket.Component;
>>  import org.apache.wicket.MarkupContainer;
>> +import org.apache.wicket.MetaDataKey;
>>  import org.apache.wicket.WicketRuntimeException;
>> +import org.apache.wicket.ajax.AjaxRequestTarget;
>> +import org.apache.wicket.core.util.string.CssUtils;
>>  import org.apache.wicket.markup.ComponentTag;
>>  import org.apache.wicket.markup.MarkupStream;
>>  import org.apache.wicket.markup.html.TransparentWebMarkupContainer;
>> @@ -36,11 +41,14 @@ import org.slf4j.LoggerFactory;
>>   * <li>Outputs the {@code for} attribute with the value equivalent to the
>> markup id of the
>>   * referenced form component</li>
>>   * <li>Appends {@code required} css class to the {@code <label>} tag if
>> the referenced form
>> - * component is required</li>
>> + * component is required. Name of the css class can be overwritten by
>> having a i18n property defined
>> + * for key AutoLabelResolver.CSS.required</li>
>>   * <li>Appends {@code error} css class to the {@code <label>} tag if the
>> referenced form component
>> - * has failed validation</li>
>> + * has failed validation. Name of the css class can be overwritten by
>> having a i18n property defined
>> + * for key AutoLabelResolver.CSS.error</li>
>>   * <li>Appends {@code disabled} css class to the {@code <label>} tag if
>> the referenced form
>> - * component has is not enabled in hierarchy</li>
>> + * component has is not enabled in hierarchy. Name of the css class can
>> be overwritten by having a i18n property defined
>> + * for key AutoLabelResolver.CSS.disabled</li>
>>   * </ul>
>>   *
>>   * <p>
>> @@ -64,6 +72,14 @@ public class AutoLabelResolver implements
>> IComponentResolver
>>
>>         static final String WICKET_FOR = ":for";
>>
>> +       public static final String CSS_REQUIRED_KEY =
>> CssUtils.key(AutoLabelResolver.class, "requried");
>> +       public static final String CSS_DISABLED_KEY =
>> CssUtils.key(AutoLabelResolver.class, "requried");
>> +       public static final String CSS_ERROR_KEY =
>> CssUtils.key(AutoLabelResolver.class, "requried");
>> +       private static final String CSS_DISABLED_DEFAULT = "disabled";
>> +       private static final String CSS_REQUIRED_DEFAULT = "required";
>> +       private static final String CSS_ERROR_DEFAULT = "error";
>> +
>> +
>>         @Override
>>         public Component resolve(final MarkupContainer container, final
>> MarkupStream markupStream,
>>                 final ComponentTag tag)
>> @@ -99,6 +115,11 @@ public class AutoLabelResolver implements
>> IComponentResolver
>>                         }
>>                 }
>>
>> +               if (component instanceof FormComponent)
>> +               {
>> +                       component.setMetaData(MARKER_KEY, new
>> AutoLabelMarker((FormComponent<?>)component));
>> +               }
>> +
>>                 return new AutoLabel("label" +
>> container.getPage().getAutoIndex(), component);
>>         }
>>
>> @@ -161,6 +182,100 @@ public class AutoLabelResolver implements
>> IComponentResolver
>>                 return null;
>>         }
>>
>> +       public static final String getLabelIdFor(Component component)
>> +       {
>> +               return component.getMarkupId() + "-w-lbl";
>> +       }
>> +
>> +       public static final MetaDataKey<AutoLabelMarker> MARKER_KEY = new
>> MetaDataKey<AutoLabelMarker>()
>> +       {
>> +       };
>> +
>> +       /**
>> +        * Marker used to track whether or not a form component has an
>> associated auto label by its mere
>> +        * presense as well as some attributes of the component across
>> requests.
>> +        *
>> +        * @author igor
>> +        *
>> +        */
>> +       public static final class AutoLabelMarker implements Serializable
>> +       {
>> +               public static final short VALID = 0x01;
>> +               public static final short REQUIRED = 0x02;
>> +               public static final short ENABLED = 0x04;
>> +
>> +               private short flags;
>> +
>> +               public AutoLabelMarker(FormComponent<?> component)
>> +               {
>> +                       setFlag(VALID, component.isValid());
>> +                       setFlag(REQUIRED, component.isRequired());
>> +                       setFlag(ENABLED, component.isEnabledInHierarchy());
>> +               }
>> +
>> +               public void updateFrom(FormComponent<?> component,
>> AjaxRequestTarget target)
>> +               {
>> +                       boolean valid = component.isValid(), required =
>> component.isRequired(), enabled = component.isEnabledInHierarchy();
>> +
>> +                       if (isValid() != valid)
>> +                       {
>> +
>> target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
>>
>
> Until now we haven't used jQuery APIs directly in the Java code.
> This makes it harder to use different impl of wicket-event/ajax js.
>
>
>> +                                       getLabelIdFor(component),
>> component.getString(CSS_ERROR_KEY, null, CSS_ERROR_DEFAULT),
>> +                                       !valid));
>> +                       }
>> +
>> +                       if (isRequired() != required)
>> +                       {
>> +
>> target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
>> +                                       getLabelIdFor(component),
>> component.getString(CSS_REQUIRED_KEY, null, CSS_REQUIRED_DEFAULT),
>> +                                       required));
>> +                       }
>> +
>> +                       if (isEnabled() != enabled)
>> +                       {
>> +
>> target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
>> +                                       getLabelIdFor(component),
>> component.getString(CSS_DISABLED_KEY, null, CSS_DISABLED_DEFAULT),
>> +                                       !enabled));
>> +                       }
>> +
>> +                       setFlag(VALID, valid);
>> +                       setFlag(REQUIRED, required);
>> +                       setFlag(ENABLED, enabled);
>> +               }
>> +
>> +               public boolean isValid()
>> +               {
>> +                       return getFlag(VALID);
>> +               }
>> +
>> +               public boolean isEnabled()
>> +               {
>> +                       return getFlag(ENABLED);
>> +               }
>> +
>> +               public boolean isRequired()
>> +               {
>> +                       return getFlag(REQUIRED);
>> +               }
>> +
>> +               private boolean getFlag(final int flag)
>> +               {
>> +                       return (flags & flag) != 0;
>> +               }
>> +
>> +               private void setFlag(final short flag, final boolean set)
>> +               {
>> +                       if (set)
>> +                       {
>> +                               flags |= flag;
>> +                       }
>> +                       else
>> +                       {
>> +                               flags &= ~flag;
>> +                       }
>> +               }
>> +       }
>> +
>>         /**
>>          * Component that is attached to the {@code <label>} tag and takes
>> care of writing out the label
>>          * text as well as setting classes on the {@code <label>} tag
>> @@ -184,23 +299,24 @@ public class AutoLabelResolver implements
>> IComponentResolver
>>                 {
>>                         super.onComponentTag(tag);
>>                         tag.put("for", component.getMarkupId());
>> +                       tag.put("id", getLabelIdFor(component));
>>
>>                         if (component instanceof FormComponent)
>>                         {
>>                                 FormComponent<?> fc =
>> (FormComponent<?>)component;
>>                                 if (fc.isRequired())
>>                                 {
>> -                                       tag.append("class", "required", "
>> ");
>> +                                       tag.append("class",
>> component.getString(CSS_REQUIRED_KEY, null, CSS_REQUIRED_DEFAULT), " ");
>>                                 }
>>                                 if (!fc.isValid())
>>                                 {
>> -                                       tag.append("class", "error", " ");
>> +                                       tag.append("class",
>> component.getString(CSS_ERROR_KEY, null, CSS_ERROR_DEFAULT), " ");
>>                                 }
>>                         }
>>
>>                         if (!component.isEnabledInHierarchy())
>>                         {
>> -                               tag.append("class", "disabled", " ");
>> +                               tag.append("class",
>> component.getString(CSS_DISABLED_KEY, null, CSS_DISABLED_DEFAULT), " ");
>>                         }
>>                 }
>>
>> @@ -213,4 +329,6 @@ public class AutoLabelResolver implements
>> IComponentResolver
>>                         return component;
>>                 }
>>         }
>> +
>> +
>>  }
>>
>>
>> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
>> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
>> index a7f07f3..a9ea6a6 100644
>> ---
>> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
>> +++
>> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
>> @@ -30,6 +30,7 @@ import org.apache.wicket.Component;
>>  import org.apache.wicket.IGenericComponent;
>>  import org.apache.wicket.Page;
>>  import org.apache.wicket.WicketRuntimeException;
>> +import org.apache.wicket.ajax.AjaxRequestTarget;
>>  import org.apache.wicket.behavior.Behavior;
>>  import org.apache.wicket.markup.ComponentTag;
>>  import org.apache.wicket.markup.MarkupStream;
>> @@ -144,10 +145,8 @@ import org.slf4j.LoggerFactory;
>>   * @param <T>
>>   *            The model object type
>>   */
>> -public class Form<T> extends WebMarkupContainer
>> -       implements
>> -               IFormSubmitListener,
>> -               IGenericComponent<T>
>> +public class Form<T> extends WebMarkupContainer implements
>> IFormSubmitListener,
>> +       IGenericComponent<T>
>>  {
>>         private static final String HIDDEN_DIV_START = "<div
>> style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">";
>>
>> @@ -778,6 +777,20 @@ public class Form<T> extends WebMarkupContainer
>>                 {
>>                         callOnError(submitter);
>>                 }
>> +
>> +
>> +               if (((WebRequest)getRequest()).isAjax())
>> +               {
>> +                       final AjaxRequestTarget target =
>> getRequestCycle().find(AjaxRequestTarget.class);
>> +                       visitChildren(FormComponent.class, new
>> IVisitor<FormComponent<?>, Void>()
>> +                       {
>> +                               @Override
>> +                               public void component(FormComponent<?>
>> component, IVisit<Void> visit)
>> +                               {
>> +                                       component.updateAutoLabels(target);
>> +                               }
>> +                       });
>> +               }
>>         }
>>
>>         /**
>> @@ -2089,7 +2102,8 @@ public class Form<T> extends WebMarkupContainer
>>          *
>>          * @author igor
>>          */
>> -       public static enum MethodMismatchResponse {
>> +       public static enum MethodMismatchResponse
>> +       {
>>                 /**
>>                  * Continue processing.
>>                  */
>>
>>
>> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
>> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
>> index 450b6bd..e4b89ed 100644
>> ---
>> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
>> +++
>> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
>> @@ -36,12 +36,15 @@ import org.apache.wicket.IConverterLocator;
>>  import org.apache.wicket.IGenericComponent;
>>  import org.apache.wicket.Localizer;
>>  import org.apache.wicket.WicketRuntimeException;
>> +import org.apache.wicket.ajax.AjaxRequestTarget;
>>  import org.apache.wicket.behavior.Behavior;
>>  import org.apache.wicket.core.util.lang.WicketObjects;
>>  import org.apache.wicket.markup.ComponentTag;
>> +import
>> org.apache.wicket.markup.html.form.AutoLabelResolver.AutoLabelMarker;
>>  import org.apache.wicket.model.IModel;
>>  import org.apache.wicket.model.IPropertyReflectionAwareModel;
>>  import org.apache.wicket.model.Model;
>> +import org.apache.wicket.protocol.http.WebApplication;
>>  import org.apache.wicket.util.convert.ConversionException;
>>  import org.apache.wicket.util.convert.IConverter;
>>  import org.apache.wicket.util.lang.Args;
>> @@ -98,11 +101,8 @@ import org.slf4j.LoggerFactory;
>>   *            The model object type
>>   *
>>   */
>> -public abstract class FormComponent<T> extends LabeledWebMarkupContainer
>> -       implements
>> -               IFormVisitorParticipant,
>> -               IFormModelUpdateListener,
>> -               IGenericComponent<T>
>> +public abstract class FormComponent<T> extends LabeledWebMarkupContainer
>> implements
>> +       IFormVisitorParticipant, IFormModelUpdateListener,
>> IGenericComponent<T>
>>  {
>>         private static final Logger logger =
>> LoggerFactory.getLogger(FormComponent.class);
>>
>> @@ -1579,6 +1579,30 @@ public abstract class FormComponent<T> extends
>> LabeledWebMarkupContainer
>>         }
>>
>>         /**
>> +        * Updates auto label css classes such as error/required during
>> ajax updates when the labels may
>> +        * not be directly repainted in the response.
>> +        *
>> +        * @param target
>> +        */
>> +       public final void updateAutoLabels(AjaxRequestTarget target)
>> +       {
>> +               if
>> (!((WebApplication)getApplication()).getUpdateAutoLabelsOnAjaxRequests())
>> +               {
>> +                       return;
>> +               }
>> +
>> +               AutoLabelMarker marker =
>> getMetaData(AutoLabelResolver.MARKER_KEY);
>> +
>> +               if (marker == null)
>> +               {
>> +                       // this component does not have an auto label
>> +                       return;
>> +               }
>> +
>> +               marker.updateFrom(this, target);
>> +       }
>> +
>> +       /**
>>          * Update the model of a {@link FormComponent} containing a {@link
>> Collection}.
>>          *
>>          * If the model object does not yet exists, a new {@link
>> ArrayList} is filled with the converted
>>
>>
>> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
>> b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
>> index ba69791..22bbfda 100644
>> ---
>> a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
>> +++
>> b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
>> @@ -394,10 +394,10 @@ public abstract class WebApplication extends
>> Application
>>         /**
>>          * Registers a replacement resource for the given javascript
>> resource. This replacement can be
>>          * another {@link JavaScriptResourceReference} for a packaged
>> resource, but it can also be an
>> -        * {@link org.apache.wicket.request.resource.UrlResourceReference}
>> to replace the resource by a resource hosted on a CDN.
>> -        * Registering a replacement will cause the resource to replaced
>> by the given resource
>> -        * throughout the application: if {@code base} is added, {@code
>> replacement} will be added
>> -        * instead.
>> +        * {@link org.apache.wicket.request.resource.UrlResourceReference}
>> to replace the resource by a
>> +        * resource hosted on a CDN. Registering a replacement will cause
>> the resource to replaced by
>> +        * the given resource throughout the application: if {@code base}
>> is added, {@code replacement}
>> +        * will be added instead.
>>          *
>>          * @param base
>>          *            The resource to replace
>> @@ -415,10 +415,10 @@ public abstract class WebApplication extends
>> Application
>>         /**
>>          * Registers a replacement resource for the given CSS resource.
>> This replacement can be another
>>          * {@link CssResourceReference} for a packaged resource, but it
>> can also be an
>> -        * {@link org.apache.wicket.request.resource.UrlResourceReference}
>> to replace the resource by a resource hosted on a CDN.
>> -        * Registering a replacement will cause the resource to replaced
>> by the given resource
>> -        * throughout the application: if {@code base} is added, {@code
>> replacement} will be added
>> -        * instead.
>> +        * {@link org.apache.wicket.request.resource.UrlResourceReference}
>> to replace the resource by a
>> +        * resource hosted on a CDN. Registering a replacement will cause
>> the resource to replaced by
>> +        * the given resource throughout the application: if {@code base}
>> is added, {@code replacement}
>> +        * will be added instead.
>>          *
>>          * @param base
>>          *            The resource to replace
>> @@ -951,9 +951,8 @@ public abstract class WebApplication extends
>> Application
>>                 return ajaxRequestTargetListeners;
>>         }
>>
>> -       private static class DefaultAjaxRequestTargetProvider
>> -               implements
>> -                       IContextProvider<AjaxRequestTarget, Page>
>> +       private static class DefaultAjaxRequestTargetProvider implements
>> +               IContextProvider<AjaxRequestTarget, Page>
>>         {
>>                 @Override
>>                 public AjaxRequestTarget get(Page page)
>> @@ -981,4 +980,19 @@ public abstract class WebApplication extends
>> Application
>>                 }
>>                 return filterFactoryManager;
>>         }
>> +
>> +       /**
>> +        * If true, auto label css classes such as {@code error} and
>> {@code required} will be updated
>> +        * after form component processing during an ajax request. This
>> allows auto labels to correctly
>> +        * reflect the state of the form component even if they are not
>> part of the ajax markup update.
>> +        *
>> +        * TODO in wicket-7 this should move into a settings object.
>> cannot move in 6.x because it
>> +        * requires a change to a setting interface.
>> +        *
>> +        * @return {@code true} iff enabled
>> +        */
>> +       public boolean getUpdateAutoLabelsOnAjaxRequests()
>> +       {
>> +               return true;
>> +       }
>>  }
>>
>>

Re: git commit: WICKET-5411 auto label auto update during ajax

Posted by Martin Grigorov <mg...@apache.org>.
On Sat, Nov 9, 2013 at 8:49 AM, <iv...@apache.org> wrote:

> Updated Branches:
>   refs/heads/wicket-6.x 4e9a83fdc -> a73209bea
>
>
> WICKET-5411 auto label auto update during ajax
>
>
> Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
> Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/a73209be
> Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/a73209be
> Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/a73209be
>
> Branch: refs/heads/wicket-6.x
> Commit: a73209beab8814a06f2e085384ad87bdf1fda212
> Parents: 4e9a83f
> Author: Igor Vaynberg <ig...@gmail.com>
> Authored: Fri Nov 8 22:48:22 2013 -0800
> Committer: Igor Vaynberg <ig...@gmail.com>
> Committed: Fri Nov 8 22:48:22 2013 -0800
>
> ----------------------------------------------------------------------
>  .../form/AjaxFormComponentUpdatingBehavior.java |   2 +-
>  .../wicket/core/util/string/CssUtils.java       |  14 ++
>  .../markup/html/form/AutoLabelResolver.java     | 130 ++++++++++++++++++-
>  .../apache/wicket/markup/html/form/Form.java    |  24 +++-
>  .../wicket/markup/html/form/FormComponent.java  |  34 ++++-
>  .../wicket/protocol/http/WebApplication.java    |  36 +++--
>  6 files changed, 212 insertions(+), 28 deletions(-)
> ----------------------------------------------------------------------
>
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> index 7eab478..bd8267c 100644
> ---
> a/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> +++
> b/wicket-core/src/main/java/org/apache/wicket/ajax/form/AjaxFormComponentUpdatingBehavior.java
> @@ -160,8 +160,8 @@ public abstract class
> AjaxFormComponentUpdatingBehavior extends AjaxEventBehavio
>                 catch (RuntimeException e)
>                 {
>                         onError(target, e);
> -
>                 }
> +               formComponent.updateAutoLabels(target);
>         }
>
>         /**
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> b/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> index a4944a3..7de8669 100644
> ---
> a/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> +++
> b/wicket-core/src/main/java/org/apache/wicket/core/util/string/CssUtils.java
> @@ -103,4 +103,18 @@ public final class CssUtils
>                 }
>                 response.write(" />");
>         }
> +
> +       /**
> +        * Get a standardized key for a CSS class.
> +        *
> +        * @param scope
> +        *            scope of CSS class
> +        * @param facet
> +        *            facet of CSS class
> +        * @return CSS key
> +        */
> +       public static String key(Class<?> scope, String facet)
> +       {
> +               return scope.getSimpleName() + ".CSS." + facet;
> +       }
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> index 562e6ed..7892fa7 100644
> ---
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> +++
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/AutoLabelResolver.java
> @@ -16,9 +16,14 @@
>   */
>  package org.apache.wicket.markup.html.form;
>
> +import java.io.Serializable;
> +
>  import org.apache.wicket.Component;
>  import org.apache.wicket.MarkupContainer;
> +import org.apache.wicket.MetaDataKey;
>  import org.apache.wicket.WicketRuntimeException;
> +import org.apache.wicket.ajax.AjaxRequestTarget;
> +import org.apache.wicket.core.util.string.CssUtils;
>  import org.apache.wicket.markup.ComponentTag;
>  import org.apache.wicket.markup.MarkupStream;
>  import org.apache.wicket.markup.html.TransparentWebMarkupContainer;
> @@ -36,11 +41,14 @@ import org.slf4j.LoggerFactory;
>   * <li>Outputs the {@code for} attribute with the value equivalent to the
> markup id of the
>   * referenced form component</li>
>   * <li>Appends {@code required} css class to the {@code <label>} tag if
> the referenced form
> - * component is required</li>
> + * component is required. Name of the css class can be overwritten by
> having a i18n property defined
> + * for key AutoLabelResolver.CSS.required</li>
>   * <li>Appends {@code error} css class to the {@code <label>} tag if the
> referenced form component
> - * has failed validation</li>
> + * has failed validation. Name of the css class can be overwritten by
> having a i18n property defined
> + * for key AutoLabelResolver.CSS.error</li>
>   * <li>Appends {@code disabled} css class to the {@code <label>} tag if
> the referenced form
> - * component has is not enabled in hierarchy</li>
> + * component has is not enabled in hierarchy. Name of the css class can
> be overwritten by having a i18n property defined
> + * for key AutoLabelResolver.CSS.disabled</li>
>   * </ul>
>   *
>   * <p>
> @@ -64,6 +72,14 @@ public class AutoLabelResolver implements
> IComponentResolver
>
>         static final String WICKET_FOR = ":for";
>
> +       public static final String CSS_REQUIRED_KEY =
> CssUtils.key(AutoLabelResolver.class, "requried");
> +       public static final String CSS_DISABLED_KEY =
> CssUtils.key(AutoLabelResolver.class, "requried");
> +       public static final String CSS_ERROR_KEY =
> CssUtils.key(AutoLabelResolver.class, "requried");
> +       private static final String CSS_DISABLED_DEFAULT = "disabled";
> +       private static final String CSS_REQUIRED_DEFAULT = "required";
> +       private static final String CSS_ERROR_DEFAULT = "error";
> +
> +
>         @Override
>         public Component resolve(final MarkupContainer container, final
> MarkupStream markupStream,
>                 final ComponentTag tag)
> @@ -99,6 +115,11 @@ public class AutoLabelResolver implements
> IComponentResolver
>                         }
>                 }
>
> +               if (component instanceof FormComponent)
> +               {
> +                       component.setMetaData(MARKER_KEY, new
> AutoLabelMarker((FormComponent<?>)component));
> +               }
> +
>                 return new AutoLabel("label" +
> container.getPage().getAutoIndex(), component);
>         }
>
> @@ -161,6 +182,100 @@ public class AutoLabelResolver implements
> IComponentResolver
>                 return null;
>         }
>
> +       public static final String getLabelIdFor(Component component)
> +       {
> +               return component.getMarkupId() + "-w-lbl";
> +       }
> +
> +       public static final MetaDataKey<AutoLabelMarker> MARKER_KEY = new
> MetaDataKey<AutoLabelMarker>()
> +       {
> +       };
> +
> +       /**
> +        * Marker used to track whether or not a form component has an
> associated auto label by its mere
> +        * presense as well as some attributes of the component across
> requests.
> +        *
> +        * @author igor
> +        *
> +        */
> +       public static final class AutoLabelMarker implements Serializable
> +       {
> +               public static final short VALID = 0x01;
> +               public static final short REQUIRED = 0x02;
> +               public static final short ENABLED = 0x04;
> +
> +               private short flags;
> +
> +               public AutoLabelMarker(FormComponent<?> component)
> +               {
> +                       setFlag(VALID, component.isValid());
> +                       setFlag(REQUIRED, component.isRequired());
> +                       setFlag(ENABLED, component.isEnabledInHierarchy());
> +               }
> +
> +               public void updateFrom(FormComponent<?> component,
> AjaxRequestTarget target)
> +               {
> +                       boolean valid = component.isValid(), required =
> component.isRequired(), enabled = component.isEnabledInHierarchy();
> +
> +                       if (isValid() != valid)
> +                       {
> +
> target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
>

Until now we haven't used jQuery APIs directly in the Java code.
This makes it harder to use different impl of wicket-event/ajax js.


> +                                       getLabelIdFor(component),
> component.getString(CSS_ERROR_KEY, null, CSS_ERROR_DEFAULT),
> +                                       !valid));
> +                       }
> +
> +                       if (isRequired() != required)
> +                       {
> +
> target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
> +                                       getLabelIdFor(component),
> component.getString(CSS_REQUIRED_KEY, null, CSS_REQUIRED_DEFAULT),
> +                                       required));
> +                       }
> +
> +                       if (isEnabled() != enabled)
> +                       {
> +
> target.appendJavaScript(String.format("$('#%s').toggleClass('%s', %s);",
> +                                       getLabelIdFor(component),
> component.getString(CSS_DISABLED_KEY, null, CSS_DISABLED_DEFAULT),
> +                                       !enabled));
> +                       }
> +
> +                       setFlag(VALID, valid);
> +                       setFlag(REQUIRED, required);
> +                       setFlag(ENABLED, enabled);
> +               }
> +
> +               public boolean isValid()
> +               {
> +                       return getFlag(VALID);
> +               }
> +
> +               public boolean isEnabled()
> +               {
> +                       return getFlag(ENABLED);
> +               }
> +
> +               public boolean isRequired()
> +               {
> +                       return getFlag(REQUIRED);
> +               }
> +
> +               private boolean getFlag(final int flag)
> +               {
> +                       return (flags & flag) != 0;
> +               }
> +
> +               private void setFlag(final short flag, final boolean set)
> +               {
> +                       if (set)
> +                       {
> +                               flags |= flag;
> +                       }
> +                       else
> +                       {
> +                               flags &= ~flag;
> +                       }
> +               }
> +       }
> +
>         /**
>          * Component that is attached to the {@code <label>} tag and takes
> care of writing out the label
>          * text as well as setting classes on the {@code <label>} tag
> @@ -184,23 +299,24 @@ public class AutoLabelResolver implements
> IComponentResolver
>                 {
>                         super.onComponentTag(tag);
>                         tag.put("for", component.getMarkupId());
> +                       tag.put("id", getLabelIdFor(component));
>
>                         if (component instanceof FormComponent)
>                         {
>                                 FormComponent<?> fc =
> (FormComponent<?>)component;
>                                 if (fc.isRequired())
>                                 {
> -                                       tag.append("class", "required", "
> ");
> +                                       tag.append("class",
> component.getString(CSS_REQUIRED_KEY, null, CSS_REQUIRED_DEFAULT), " ");
>                                 }
>                                 if (!fc.isValid())
>                                 {
> -                                       tag.append("class", "error", " ");
> +                                       tag.append("class",
> component.getString(CSS_ERROR_KEY, null, CSS_ERROR_DEFAULT), " ");
>                                 }
>                         }
>
>                         if (!component.isEnabledInHierarchy())
>                         {
> -                               tag.append("class", "disabled", " ");
> +                               tag.append("class",
> component.getString(CSS_DISABLED_KEY, null, CSS_DISABLED_DEFAULT), " ");
>                         }
>                 }
>
> @@ -213,4 +329,6 @@ public class AutoLabelResolver implements
> IComponentResolver
>                         return component;
>                 }
>         }
> +
> +
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> index a7f07f3..a9ea6a6 100644
> ---
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> +++
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
> @@ -30,6 +30,7 @@ import org.apache.wicket.Component;
>  import org.apache.wicket.IGenericComponent;
>  import org.apache.wicket.Page;
>  import org.apache.wicket.WicketRuntimeException;
> +import org.apache.wicket.ajax.AjaxRequestTarget;
>  import org.apache.wicket.behavior.Behavior;
>  import org.apache.wicket.markup.ComponentTag;
>  import org.apache.wicket.markup.MarkupStream;
> @@ -144,10 +145,8 @@ import org.slf4j.LoggerFactory;
>   * @param <T>
>   *            The model object type
>   */
> -public class Form<T> extends WebMarkupContainer
> -       implements
> -               IFormSubmitListener,
> -               IGenericComponent<T>
> +public class Form<T> extends WebMarkupContainer implements
> IFormSubmitListener,
> +       IGenericComponent<T>
>  {
>         private static final String HIDDEN_DIV_START = "<div
> style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">";
>
> @@ -778,6 +777,20 @@ public class Form<T> extends WebMarkupContainer
>                 {
>                         callOnError(submitter);
>                 }
> +
> +
> +               if (((WebRequest)getRequest()).isAjax())
> +               {
> +                       final AjaxRequestTarget target =
> getRequestCycle().find(AjaxRequestTarget.class);
> +                       visitChildren(FormComponent.class, new
> IVisitor<FormComponent<?>, Void>()
> +                       {
> +                               @Override
> +                               public void component(FormComponent<?>
> component, IVisit<Void> visit)
> +                               {
> +                                       component.updateAutoLabels(target);
> +                               }
> +                       });
> +               }
>         }
>
>         /**
> @@ -2089,7 +2102,8 @@ public class Form<T> extends WebMarkupContainer
>          *
>          * @author igor
>          */
> -       public static enum MethodMismatchResponse {
> +       public static enum MethodMismatchResponse
> +       {
>                 /**
>                  * Continue processing.
>                  */
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> index 450b6bd..e4b89ed 100644
> ---
> a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> +++
> b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
> @@ -36,12 +36,15 @@ import org.apache.wicket.IConverterLocator;
>  import org.apache.wicket.IGenericComponent;
>  import org.apache.wicket.Localizer;
>  import org.apache.wicket.WicketRuntimeException;
> +import org.apache.wicket.ajax.AjaxRequestTarget;
>  import org.apache.wicket.behavior.Behavior;
>  import org.apache.wicket.core.util.lang.WicketObjects;
>  import org.apache.wicket.markup.ComponentTag;
> +import
> org.apache.wicket.markup.html.form.AutoLabelResolver.AutoLabelMarker;
>  import org.apache.wicket.model.IModel;
>  import org.apache.wicket.model.IPropertyReflectionAwareModel;
>  import org.apache.wicket.model.Model;
> +import org.apache.wicket.protocol.http.WebApplication;
>  import org.apache.wicket.util.convert.ConversionException;
>  import org.apache.wicket.util.convert.IConverter;
>  import org.apache.wicket.util.lang.Args;
> @@ -98,11 +101,8 @@ import org.slf4j.LoggerFactory;
>   *            The model object type
>   *
>   */
> -public abstract class FormComponent<T> extends LabeledWebMarkupContainer
> -       implements
> -               IFormVisitorParticipant,
> -               IFormModelUpdateListener,
> -               IGenericComponent<T>
> +public abstract class FormComponent<T> extends LabeledWebMarkupContainer
> implements
> +       IFormVisitorParticipant, IFormModelUpdateListener,
> IGenericComponent<T>
>  {
>         private static final Logger logger =
> LoggerFactory.getLogger(FormComponent.class);
>
> @@ -1579,6 +1579,30 @@ public abstract class FormComponent<T> extends
> LabeledWebMarkupContainer
>         }
>
>         /**
> +        * Updates auto label css classes such as error/required during
> ajax updates when the labels may
> +        * not be directly repainted in the response.
> +        *
> +        * @param target
> +        */
> +       public final void updateAutoLabels(AjaxRequestTarget target)
> +       {
> +               if
> (!((WebApplication)getApplication()).getUpdateAutoLabelsOnAjaxRequests())
> +               {
> +                       return;
> +               }
> +
> +               AutoLabelMarker marker =
> getMetaData(AutoLabelResolver.MARKER_KEY);
> +
> +               if (marker == null)
> +               {
> +                       // this component does not have an auto label
> +                       return;
> +               }
> +
> +               marker.updateFrom(this, target);
> +       }
> +
> +       /**
>          * Update the model of a {@link FormComponent} containing a {@link
> Collection}.
>          *
>          * If the model object does not yet exists, a new {@link
> ArrayList} is filled with the converted
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/a73209be/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> ----------------------------------------------------------------------
> diff --git
> a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> index ba69791..22bbfda 100644
> ---
> a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> +++
> b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
> @@ -394,10 +394,10 @@ public abstract class WebApplication extends
> Application
>         /**
>          * Registers a replacement resource for the given javascript
> resource. This replacement can be
>          * another {@link JavaScriptResourceReference} for a packaged
> resource, but it can also be an
> -        * {@link org.apache.wicket.request.resource.UrlResourceReference}
> to replace the resource by a resource hosted on a CDN.
> -        * Registering a replacement will cause the resource to replaced
> by the given resource
> -        * throughout the application: if {@code base} is added, {@code
> replacement} will be added
> -        * instead.
> +        * {@link org.apache.wicket.request.resource.UrlResourceReference}
> to replace the resource by a
> +        * resource hosted on a CDN. Registering a replacement will cause
> the resource to replaced by
> +        * the given resource throughout the application: if {@code base}
> is added, {@code replacement}
> +        * will be added instead.
>          *
>          * @param base
>          *            The resource to replace
> @@ -415,10 +415,10 @@ public abstract class WebApplication extends
> Application
>         /**
>          * Registers a replacement resource for the given CSS resource.
> This replacement can be another
>          * {@link CssResourceReference} for a packaged resource, but it
> can also be an
> -        * {@link org.apache.wicket.request.resource.UrlResourceReference}
> to replace the resource by a resource hosted on a CDN.
> -        * Registering a replacement will cause the resource to replaced
> by the given resource
> -        * throughout the application: if {@code base} is added, {@code
> replacement} will be added
> -        * instead.
> +        * {@link org.apache.wicket.request.resource.UrlResourceReference}
> to replace the resource by a
> +        * resource hosted on a CDN. Registering a replacement will cause
> the resource to replaced by
> +        * the given resource throughout the application: if {@code base}
> is added, {@code replacement}
> +        * will be added instead.
>          *
>          * @param base
>          *            The resource to replace
> @@ -951,9 +951,8 @@ public abstract class WebApplication extends
> Application
>                 return ajaxRequestTargetListeners;
>         }
>
> -       private static class DefaultAjaxRequestTargetProvider
> -               implements
> -                       IContextProvider<AjaxRequestTarget, Page>
> +       private static class DefaultAjaxRequestTargetProvider implements
> +               IContextProvider<AjaxRequestTarget, Page>
>         {
>                 @Override
>                 public AjaxRequestTarget get(Page page)
> @@ -981,4 +980,19 @@ public abstract class WebApplication extends
> Application
>                 }
>                 return filterFactoryManager;
>         }
> +
> +       /**
> +        * If true, auto label css classes such as {@code error} and
> {@code required} will be updated
> +        * after form component processing during an ajax request. This
> allows auto labels to correctly
> +        * reflect the state of the form component even if they are not
> part of the ajax markup update.
> +        *
> +        * TODO in wicket-7 this should move into a settings object.
> cannot move in 6.x because it
> +        * requires a change to a setting interface.
> +        *
> +        * @return {@code true} iff enabled
> +        */
> +       public boolean getUpdateAutoLabelsOnAjaxRequests()
> +       {
> +               return true;
> +       }
>  }
>
>