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.html;
016    
017    import java.util.HashMap;
018    import java.util.Map;
019    
020    import org.apache.hivemind.ApplicationRuntimeException;
021    import org.apache.tapestry.AbstractComponent;
022    import org.apache.tapestry.IAsset;
023    import org.apache.tapestry.IMarkupWriter;
024    import org.apache.tapestry.IRequestCycle;
025    import org.apache.tapestry.IScript;
026    import org.apache.tapestry.PageRenderSupport;
027    import org.apache.tapestry.Tapestry;
028    import org.apache.tapestry.TapestryUtils;
029    import org.apache.tapestry.components.ILinkComponent;
030    
031    /**
032     * Combines a link component (such as
033     * {@link org.apache.tapestry.link.DirectLink}) with an <img> and
034     * JavaScript code to create a rollover effect that works with both Netscape
035     * Navigator and Internet Explorer. [ <a
036     * href="../../../../../ComponentReference/Rollover.html">Component Reference
037     * </a>]
038     * 
039     * @author Howard Lewis Ship
040     */
041    
042    public abstract class Rollover extends AbstractComponent
043    {
044    
045        /**
046         * Converts an {@link IAsset}binding into a usable URL. Returns null if the
047         * binding does not exist or the binding's value is null.
048         */
049    
050        protected String getAssetURL(IAsset asset)
051        {
052            if (asset == null) return null;
053    
054            return asset.buildURL();
055        }
056    
057        protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
058        {
059            // No body, so we skip it all if not rewinding (assumes no side effects
060            // on
061            // accessors).
062    
063            if (cycle.isRewinding()) 
064                return;
065    
066            String imageURL = null;
067            String mouseOverURL = null;
068            String mouseOutURL = null;
069            boolean dynamic = false;
070            String imageId = null;
071    
072            PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, this);
073    
074            ILinkComponent serviceLink = (ILinkComponent) cycle.getAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME);
075            
076            if (serviceLink == null)
077                throw new ApplicationRuntimeException(Tapestry
078                        .getMessage("Rollover.must-be-contained-by-link"), this, null, null);
079    
080            boolean linkDisabled = serviceLink.isDisabled();
081    
082            if (linkDisabled)
083            {
084                imageURL = getAssetURL(getDisabled());
085    
086                if (imageURL == null) imageURL = getAssetURL(getImage());
087            }
088            else
089            {
090                imageURL = getAssetURL(getImage());
091                mouseOverURL = getAssetURL(getMouseOver());
092                mouseOutURL = getAssetURL(getMouseOut());
093    
094                dynamic = (mouseOverURL != null) || (mouseOutURL != null);
095            }
096    
097            if (imageURL == null)
098                throw Tapestry.createRequiredParameterException(this, "image");
099    
100            writer.beginEmpty("img");
101    
102            writer.attribute("src", imageURL);
103    
104            if (dynamic)
105            {
106                if (mouseOverURL == null) 
107                    mouseOverURL = imageURL;
108    
109                if (mouseOutURL == null) 
110                    mouseOutURL = imageURL;
111    
112                imageId = writeScript(cycle, pageRenderSupport, serviceLink, mouseOverURL, mouseOutURL);
113                
114                writer.attribute("id", imageId);
115            }
116            
117            renderInformalParameters(writer, cycle);
118    
119            writer.closeTag();
120    
121        }
122    
123        // Injected
124    
125        public abstract IScript getScript();
126    
127        private String writeScript(IRequestCycle cycle, PageRenderSupport pageRenderSupport, ILinkComponent link,
128                String mouseOverImageURL, String mouseOutImageURL)
129        {
130            String imageId = pageRenderSupport.getUniqueString(getId());
131            
132            String preloadedMouseOverImageURL = pageRenderSupport.getPreloadedImageReference(this, mouseOverImageURL);
133            String preloadedMouseOutImageURL = pageRenderSupport.getPreloadedImageReference(this, mouseOutImageURL);
134            
135            Map symbols = new HashMap();
136            
137            symbols.put("link", link);
138            symbols.put("imageId", imageId);
139            symbols.put("mouseOverImageURL", preloadedMouseOverImageURL);
140            symbols.put("mouseOutImageURL", preloadedMouseOutImageURL);
141            
142            getScript().execute(this, cycle, pageRenderSupport, symbols);
143            
144            return imageId;
145        }
146    
147        public abstract IAsset getMouseOut();
148    
149        public abstract IAsset getDisabled();
150    
151        public abstract IAsset getMouseOver();
152    
153        public abstract IAsset getImage();
154    }