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