001 // Copyright 2007, 2008, 2009, 2010 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.internal;
016
017 import org.apache.tapestry5.*;
018 import org.apache.tapestry5.dom.Element;
019 import org.apache.tapestry5.services.Environment;
020 import org.apache.tapestry5.services.FormSupport;
021
022 /**
023 * Default implementation that writes an attribute into fields or labels that are in error.
024 */
025 public final class DefaultValidationDecorator extends BaseValidationDecorator
026 {
027 private final Environment environment;
028
029 private final Asset spacerAsset;
030
031 private final MarkupWriter markupWriter;
032
033 /**
034 * @param environment
035 * used to locate objects and services during the render
036 * @param spacerAsset
037 * asset for a one-pixel spacer image used as a placeholder for the error marker icon
038 * @param markupWriter
039 */
040 public DefaultValidationDecorator(Environment environment, Asset spacerAsset, MarkupWriter markupWriter)
041 {
042 this.environment = environment;
043 this.spacerAsset = spacerAsset;
044 this.markupWriter = markupWriter;
045 }
046
047 @Override
048 public void insideField(Field field)
049 {
050 if (inError(field))
051 addErrorClassToCurrentElement();
052 }
053
054 @Override
055 public void insideLabel(Field field, Element element)
056 {
057 if (field == null)
058 return;
059
060 if (inError(field))
061 element.addClassName(CSSClassConstants.ERROR);
062 }
063
064 /**
065 * Writes an icon for field after the field. The icon has the same id as the field, with ":icon" appended. This is
066 * expected by the default client-side JavaScript. The icon's src is a blank spacer image (this is to allow the
067 * image displayed to be overridden via CSS). The icon's CSS class is "t-error-icon", with "t-invisible" added
068 * if the field is not in error when rendered. If client validation is not enabled for the form containing the
069 * field and the field is not in error, then the error icon itself is not rendered.
070 *
071 * @param field
072 * which just completed rendering itself
073 */
074 @Override
075 public void afterField(Field field)
076 {
077 boolean inError = inError(field);
078
079 boolean clientValidationEnabled = getFormSupport().isClientValidationEnabled();
080
081 if (inError || clientValidationEnabled)
082 {
083 String iconId = field.getClientId() + "_icon";
084
085 String cssClass = inError ? "t-error-icon" : "t-error-icon t-invisible";
086
087 markupWriter.element("img", "src", spacerAsset.toClientURL(), "alt", "", "class", cssClass, "id", iconId);
088 markupWriter.end();
089 }
090
091 }
092
093 private FormSupport getFormSupport()
094 {
095 return environment.peekRequired(FormSupport.class);
096 }
097
098 private boolean inError(Field field)
099 {
100 ValidationTracker tracker = environment.peekRequired(ValidationTracker.class);
101
102 return tracker.inError(field);
103 }
104
105 private void addErrorClassToCurrentElement()
106 {
107 markupWriter.getElement().addClassName(CSSClassConstants.ERROR);
108 }
109 }