001 // Copyright 2004, 2005 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.tapestry.link;
016
017 import java.util.ArrayList;
018 import java.util.HashMap;
019 import java.util.Iterator;
020 import java.util.List;
021 import java.util.Map;
022
023 import org.apache.tapestry.AbstractComponent;
024 import org.apache.tapestry.IMarkupWriter;
025 import org.apache.tapestry.IRequestCycle;
026 import org.apache.tapestry.PageRenderSupport;
027 import org.apache.tapestry.TapestryUtils;
028 import org.apache.tapestry.components.ILinkComponent;
029 import org.apache.tapestry.components.LinkEventType;
030 import org.apache.tapestry.engine.ILink;
031
032 /**
033 * Base class for implementations of {@link ILinkComponent}. Includes a disabled attribute (that
034 * should be bound to a disabled parameter), an anchor attribute, and a renderer attribute (that
035 * should be bound to a renderer parameter). A default, shared instance of
036 * {@link org.apache.tapestry.link.DefaultLinkRenderer} is used when no specific renderer is
037 * provided.
038 *
039 * @author Howard Lewis Ship
040 */
041
042 public abstract class AbstractLinkComponent extends AbstractComponent implements ILinkComponent
043 {
044 private Map _eventHandlers;
045
046 public abstract boolean isDisabled();
047
048 /**
049 * Adds an event handler (typically, from a wrapped component such as a
050 * {@link org.apache.tapestry.html.Rollover}).
051 */
052
053 public void addEventHandler(LinkEventType eventType, String functionName)
054 {
055 Object currentValue;
056
057 if (_eventHandlers == null)
058 _eventHandlers = new HashMap();
059
060 currentValue = _eventHandlers.get(eventType);
061
062 // The first value is added as a String
063
064 if (currentValue == null)
065 {
066 _eventHandlers.put(eventType, functionName);
067 return;
068 }
069
070 // When adding the second value, convert to a List
071
072 if (currentValue instanceof String)
073 {
074 List list = new ArrayList();
075 list.add(currentValue);
076 list.add(functionName);
077
078 _eventHandlers.put(eventType, list);
079 return;
080 }
081
082 // For the third and up, add the new function to the List
083
084 List list = (List) currentValue;
085 list.add(functionName);
086 }
087
088 /**
089 * Renders the link by delegating to an instance of {@link ILinkRenderer}.
090 */
091
092 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
093 {
094 getRenderer().renderLink(writer, cycle, this);
095 }
096
097 protected void cleanupAfterRender(IRequestCycle cycle)
098 {
099 super.cleanupAfterRender(cycle);
100
101 _eventHandlers = null;
102 }
103
104 protected void writeEventHandlers(IMarkupWriter writer, IRequestCycle cycle)
105 {
106 String name = null;
107
108 if (_eventHandlers == null)
109 return;
110
111 PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, this);
112
113 Iterator i = _eventHandlers.entrySet().iterator();
114
115 while (i.hasNext())
116 {
117 Map.Entry entry = (Map.Entry) i.next();
118 LinkEventType type = (LinkEventType) entry.getKey();
119
120 name = writeEventHandler(
121 writer,
122 pageRenderSupport,
123 name,
124 type.getAttributeName(),
125 entry.getValue());
126 }
127
128 }
129
130 protected String writeEventHandler(IMarkupWriter writer, PageRenderSupport pageRenderSupport,
131 String name, String attributeName, Object value)
132 {
133 String wrapperFunctionName;
134
135 if (value instanceof String)
136 {
137 wrapperFunctionName = (String) value;
138 }
139 else
140 {
141 String finalName = name == null ? pageRenderSupport.getUniqueString("Link") : name;
142
143 wrapperFunctionName = attributeName + "_" + finalName;
144
145 StringBuffer buffer = new StringBuffer();
146
147 buffer.append("function ");
148 buffer.append(wrapperFunctionName);
149 buffer.append(" ()\n{\n");
150
151 Iterator i = ((List) value).iterator();
152 while (i.hasNext())
153 {
154 String functionName = (String) i.next();
155 buffer.append(" ");
156 buffer.append(functionName);
157 buffer.append("();\n");
158 }
159
160 buffer.append("}\n\n");
161
162 pageRenderSupport.addBodyScript(this, buffer.toString());
163 }
164
165 writer.attribute(attributeName, "javascript:" + wrapperFunctionName + "();");
166
167 return name;
168 }
169
170 /** @since 3.0 * */
171
172 public abstract ILinkRenderer getRenderer();
173
174 public abstract void setRenderer(ILinkRenderer renderer);
175
176 public void renderAdditionalAttributes(IMarkupWriter writer, IRequestCycle cycle)
177 {
178 renderIdAttribute(writer, cycle);
179
180 writeEventHandlers(writer, cycle);
181
182 // Generate additional attributes from informal parameters.
183
184 renderInformalParameters(writer, cycle);
185 }
186
187 public abstract String getAnchor();
188
189 public ILink getLink(IRequestCycle cycle)
190 {
191 return null;
192 }
193
194 /**
195 * Sets the renderer parameter property to its default value
196 * {@link DefaultLinkRenderer#SHARED_INSTANCE}.
197 *
198 * @since 3.0
199 */
200 protected void finishLoad()
201 {
202 setRenderer(DefaultLinkRenderer.SHARED_INSTANCE);
203 }
204
205 }