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