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 }