Coverage Report - org.apache.tapestry.link.DefaultLinkRenderer
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultLinkRenderer
72% 
77% 
2.667
 
 1  
 // Copyright 2004, 2005 The Apache Software Foundation
 2  
 //
 3  
 // Licensed under the Apache License, Version 2.0 (the "License");
 4  
 // you may not use this file except in compliance with the License.
 5  
 // You may obtain a copy of the License at
 6  
 //
 7  
 //     http://www.apache.org/licenses/LICENSE-2.0
 8  
 //
 9  
 // Unless required by applicable law or agreed to in writing, software
 10  
 // distributed under the License is distributed on an "AS IS" BASIS,
 11  
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 // See the License for the specific language governing permissions and
 13  
 // limitations under the License.
 14  
 
 15  
 package org.apache.tapestry.link;
 16  
 
 17  
 import org.apache.hivemind.ApplicationRuntimeException;
 18  
 import org.apache.hivemind.HiveMind;
 19  
 import org.apache.tapestry.*;
 20  
 import org.apache.tapestry.components.ILinkComponent;
 21  
 import org.apache.tapestry.engine.ILink;
 22  
 import org.apache.tapestry.util.ScriptUtils;
 23  
 
 24  
 import java.util.HashMap;
 25  
 import java.util.List;
 26  
 import java.util.Map;
 27  
 
 28  
 /**
 29  
  * Default implementation of {@link org.apache.tapestry.link.ILinkRenderer},
 30  
  * which does nothing special. Can be used as a base class to provide additional
 31  
  * handling.
 32  
  * 
 33  
  * @since 3.0
 34  
  */
 35  
 
 36  10
 public class DefaultLinkRenderer implements ILinkRenderer
 37  
 {
 38  
 
 39  
     /**
 40  
      * A shared instance used as a default for any link that doesn't explicitly
 41  
      * override.
 42  
      */
 43  
 
 44  1
     public static final ILinkRenderer SHARED_INSTANCE = new DefaultLinkRenderer();
 45  
 
 46  
     public void renderLink(IMarkupWriter writer, IRequestCycle cycle, ILinkComponent linkComponent)
 47  
     {
 48  9
         IMarkupWriter wrappedWriter = null;
 49  
         
 50  9
         if (cycle.getAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME) != null)
 51  1
             throw new ApplicationRuntimeException(LinkMessages.noNesting(), linkComponent, null, null);
 52  
         
 53  8
         cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, linkComponent);
 54  
         
 55  8
         boolean hasBody = getHasBody();
 56  
 
 57  8
         boolean disabled = linkComponent.isDisabled() || cycle.isRewinding();
 58  
 
 59  8
         if (!disabled)
 60  
         {
 61  4
             if (hasBody)
 62  3
                 writer.begin(getElement());
 63  
             else 
 64  1
                 writer.beginEmpty(getElement());
 65  
             
 66  4
             linkComponent.renderAdditionalAttributes(writer, cycle);
 67  
             
 68  4
             writer.attribute(getUrlAttribute(), constructURL(linkComponent, cycle));
 69  
             
 70  4
             String target = linkComponent.getTarget();
 71  
             
 72  4
             if (HiveMind.isNonBlank(target))
 73  3
                 writer.attribute(getTargetAttribute(), target);
 74  
             
 75  5
             if (DirectLink.class.isInstance(linkComponent)) {
 76  0
                 DirectLink direct = (DirectLink)linkComponent;
 77  
                 
 78  0
                 renderAsyncParams(writer, cycle, direct);
 79  
             }
 80  
             
 81  4
             beforeBodyRender(writer, cycle, linkComponent);
 82  
             
 83  
             // Allow the wrapped components a chance to render.
 84  
             // Along the way, they may interact with this component
 85  
             // and cause the name variable to get set.
 86  
             
 87  4
             wrappedWriter = writer.getNestedWriter();
 88  4
         } else 
 89  4
             wrappedWriter = writer;
 90  
         
 91  8
         if (hasBody) 
 92  6
             linkComponent.renderBody(wrappedWriter, cycle);
 93  
         
 94  8
         if (!disabled) {
 95  
             
 96  4
             afterBodyRender(writer, cycle, linkComponent);
 97  
             
 98  
             // linkComponent.renderAdditionalAttributes(writer, cycle);
 99  
             
 100  4
             if (hasBody) {
 101  3
                 wrappedWriter.close();
 102  
                 
 103  
                 // Close the <element> tag
 104  
                 
 105  3
                 writer.end();
 106  
             } else 
 107  1
                 writer.closeTag();
 108  
         }
 109  
         
 110  8
         cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME);
 111  8
     }
 112  
 
 113  
     /**
 114  
      * Converts the EngineServiceLink into a URI or URL. This implementation
 115  
      * gets the scheme and anchor from the component (both of which may be
 116  
      * null), and invokes
 117  
      * {@link ILink#getURL(String, String, int, String, boolean)}.
 118  
      */
 119  
 
 120  
     protected String constructURL(ILinkComponent component, IRequestCycle cycle)
 121  
     {
 122  4
         ILink link = component.getLink(cycle);
 123  
         
 124  4
         String scheme = component.getScheme();
 125  4
         Integer port = component.getPort();
 126  4
         int portI = (port == null) ? 0 : port.intValue();
 127  4
         String anchor = component.getAnchor();
 128  
         
 129  4
         return link.getURL(scheme, null, portI, anchor, true);
 130  
     }
 131  
 
 132  
     /**
 133  
      * Invoked after the href attribute has been written but before the body of
 134  
      * the link is rendered (but only if the link is not disabled).
 135  
      * <p>
 136  
      * This implementation does nothing.
 137  
      * </p>
 138  
      *
 139  
      * @param writer
 140  
      *          Markup writer.
 141  
      * @param cycle
 142  
      *          Current request cycle.
 143  
      * @param link
 144  
      *          The link component being rendered.
 145  
      */
 146  
 
 147  
     protected void beforeBodyRender(IMarkupWriter writer, IRequestCycle cycle, ILinkComponent link)
 148  
     {
 149  2
     }
 150  
 
 151  
     /**
 152  
      * Invoked after the body of the link is rendered, but before
 153  
      * {@link ILinkComponent#renderAdditionalAttributes(IMarkupWriter, IRequestCycle)}is
 154  
      * invoked (but only if the link is not disabled).
 155  
      * 
 156  
      * <p>
 157  
      * This implementation does nothing.
 158  
      * </p>
 159  
      * @param writer
 160  
      *          Markup writer.
 161  
      * @param cycle
 162  
      *          Current request cycle.
 163  
      * @param link
 164  
      *          The link component being rendered.
 165  
      */
 166  
 
 167  
     protected void afterBodyRender(IMarkupWriter writer, IRequestCycle cycle, ILinkComponent link)
 168  
     {
 169  2
     }
 170  
 
 171  
     /**
 172  
      * For {@link DirectLink} components only, manages writing out event handlers for link
 173  
      * if any of the dynamic (async/json/etc) parameters are set on the component.
 174  
      * 
 175  
      * <p>
 176  
      *  Will try to write the logic into the <code>onClick</code> attribute of the link 
 177  
      *  if not bound, otherwise it will render it using the {@link DirectLink#getScript()} script.
 178  
      * </p>
 179  
      * 
 180  
      * @param writer
 181  
      *          The writer to render attributes into.
 182  
      * @param cycle
 183  
      *          The current request cycle.
 184  
      * @param link
 185  
      *          The component link being rendered for.
 186  
      */
 187  
     protected void renderAsyncParams(IMarkupWriter writer, IRequestCycle cycle, DirectLink link)
 188  
     {
 189  0
         List comps = link.getUpdateComponents();
 190  
         
 191  0
         if (!link.isAsync() && !link.isJson() 
 192  
                 && (comps == null
 193  
                 || comps.size() <= 0))
 194  0
             return;
 195  
         
 196  0
         if (!link.isParameterBound("onclick") && !link.isParameterBound("onClick")) {
 197  0
             writer.attribute("onclick", 
 198  
                     "return tapestry.linkOnClick(this.href,'" + link.getClientId() + "', " + link.isJson() + ")");
 199  0
             return;
 200  
         }
 201  
         
 202  0
         PageRenderSupport prs = TapestryUtils.getPageRenderSupport(cycle, link);
 203  
         
 204  0
         if (prs == null)
 205  0
             return;
 206  
         
 207  0
         Map parms = new HashMap();
 208  
         
 209  0
         parms.put("component", link);
 210  0
         parms.put("json", Boolean.valueOf(link.isJson()));
 211  0
         parms.put("key", ScriptUtils.functionHash("onclick" + link.hashCode()));
 212  
         
 213  
         // execute script template
 214  
         
 215  0
         link.getScript().execute(link, cycle, prs, parms);
 216  0
     }
 217  
     
 218  
     /** @since 3.0 * */
 219  
 
 220  
     protected String getElement()
 221  
     {
 222  2
         return "a";
 223  
     }
 224  
 
 225  
     protected String getUrlAttribute()
 226  
     {
 227  2
         return "href";
 228  
     }
 229  
 
 230  
     protected String getTargetAttribute()
 231  
     {
 232  1
         return "target";
 233  
     }
 234  
 
 235  
     protected boolean getHasBody()
 236  
     {
 237  4
         return true;
 238  
     }
 239  
 }