001 // Copyright 2008 Thiago H. de Paula Figueiredo
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 br.com.arsmachina.tapestrycrud.components;
016
017
018 import org.apache.tapestry5.BindingConstants;
019 import org.apache.tapestry5.ComponentResources;
020 import org.apache.tapestry5.Field;
021 import org.apache.tapestry5.MarkupWriter;
022 import org.apache.tapestry5.ValidationDecorator;
023 import org.apache.tapestry5.annotations.AfterRender;
024 import org.apache.tapestry5.annotations.BeginRender;
025 import org.apache.tapestry5.annotations.Environmental;
026 import org.apache.tapestry5.annotations.IncludeStylesheet;
027 import org.apache.tapestry5.annotations.Mixin;
028 import org.apache.tapestry5.annotations.Parameter;
029 import org.apache.tapestry5.annotations.SupportsInformalParameters;
030 import org.apache.tapestry5.corelib.components.Label;
031 import org.apache.tapestry5.corelib.mixins.DiscardBody;
032 import org.apache.tapestry5.dom.Element;
033 import org.apache.tapestry5.ioc.annotations.Inject;
034 import org.apache.tapestry5.services.Heartbeat;
035
036 import br.com.arsmachina.tapestrycrud.Constants;
037
038 /**
039 * <p>
040 * {@link Label} subclass that always ignores its body and generates the label name from the
041 * corresponding field id.
042 * </p>
043 * <p>
044 * This class' code was initially copied from {@link Label}, as one of its methods (<code>afterRender</code>)
045 * has package visibility and thus cannot be overriden.
046 * </p>
047 *
048 * @author Thiago H. de Paula Figueiredo
049 */
050 @SupportsInformalParameters
051 @IncludeStylesheet(Constants.TAPESTRY_CRUD_CSS_ASSET)
052 public class ImprovedLabel {
053
054 /**
055 * Discards the body of this class.
056 */
057 @SuppressWarnings("unused")
058 @Mixin
059 private DiscardBody discardBody;
060
061 /**
062 * The for parameter is used to identify the {@link Field} linked to this label (it is named
063 * this way because it results in the for attribute of the label element).
064 */
065 @Parameter(name = "for", required = true, defaultPrefix = BindingConstants.COMPONENT)
066 private Field field;
067
068 @Environmental
069 private Heartbeat heartbeat;
070
071 @Environmental
072 private ValidationDecorator decorator;
073
074 @Inject
075 private ComponentResources resources;
076
077 private Element labelElement;
078
079 @BeginRender
080 void begin(MarkupWriter writer) {
081 final Field field = this.field;
082
083 decorator.beforeLabel(field);
084
085 labelElement = writer.element("label");
086
087 resources.renderInformalParameters(writer);
088
089 // Since we don't know if the field has rendered yet, we need to defer writing the for and
090 // id
091 // attributes until we know the field has rendered (and set its clientId property). That's
092 // exactly what Heartbeat is for.
093
094 Runnable command = new Runnable() {
095
096 public void run() {
097 String fieldId = field.getClientId();
098
099 labelElement.forceAttributes("for", fieldId, "id", fieldId + ":label");
100
101 decorator.insideLabel(field, labelElement);
102 }
103 };
104
105 heartbeat.defer(command);
106 }
107
108 @AfterRender
109 void after(MarkupWriter writer) {
110 // If the Label element has a body that renders some non-blank output, that takes
111 // precendence
112 // over the label string provided by the field.
113
114 // removed code from label. the rest was not modified.
115
116 // boolean bodyIsBlank = InternalUtils.isBlank(labelElement.getChildMarkup());
117 //
118 // if (bodyIsBlank)
119 // writer.write(field.getLabel());
120
121 writer.write(field.getLabel());
122
123 writer.end(); // label
124
125 decorator.afterLabel(field);
126
127 }
128 }