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    import org.apache.tapestry.components.LinkEventType;
031    
032    /**
033     * Combines a link component (such as {@link org.apache.tapestry.link.DirectLink}) with an
034     * <img> and 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 </a>]
037     * 
038     * @author Howard Lewis Ship
039     */
040    
041    public abstract class Rollover extends AbstractComponent
042    {
043        /**
044         * Converts an {@link IAsset}binding into a usable URL. Returns null if the binding does not
045         * exist or the binding's value is null.
046         */
047    
048        protected String getAssetURL(IAsset asset, IRequestCycle cycle)
049        {
050            if (asset == null)
051                return null;
052    
053            return asset.buildURL(cycle);
054        }
055    
056        protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
057        {
058            // No body, so we skip it all if not rewinding (assumes no side effects on
059            // accessors).
060    
061            if (cycle.isRewinding())
062                return;
063    
064            String imageURL = null;
065            String focusURL = null;
066            String blurURL = null;
067            boolean dynamic = false;
068            String imageName = null;
069    
070            PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, this);
071    
072            ILinkComponent serviceLink = (ILinkComponent) cycle
073                    .getAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME);
074    
075            if (serviceLink == null)
076                throw new ApplicationRuntimeException(Tapestry
077                        .getMessage("Rollover.must-be-contained-by-link"), this, null, null);
078    
079            boolean linkDisabled = serviceLink.isDisabled();
080    
081            if (linkDisabled)
082            {
083                imageURL = getAssetURL(getDisabled(), cycle);
084    
085                if (imageURL == null)
086                    imageURL = getAssetURL(getImage(), cycle);
087            }
088            else
089            {
090                imageURL = getAssetURL(getImage(), cycle);
091                focusURL = getAssetURL(getFocus(), cycle);
092                blurURL = getAssetURL(getBlur(), cycle);
093    
094                dynamic = (focusURL != null) || (blurURL != 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 (focusURL == null)
107                    focusURL = imageURL;
108    
109                if (blurURL == null)
110                    blurURL = imageURL;
111    
112                imageName = writeScript(cycle, pageRenderSupport, serviceLink, focusURL, blurURL);
113    
114                writer.attribute("name", imageName);
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,
128                ILinkComponent link, String focusURL, String blurURL)
129        {
130            String imageName = pageRenderSupport.getUniqueString(getId());
131            String focusImageURL = pageRenderSupport.getPreloadedImageReference(focusURL);
132            String blurImageURL = pageRenderSupport.getPreloadedImageReference(blurURL);
133    
134            Map symbols = new HashMap();
135    
136            symbols.put("imageName", imageName);
137            symbols.put("focusImageURL", focusImageURL);
138            symbols.put("blurImageURL", blurImageURL);
139    
140            getScript().execute(cycle, pageRenderSupport, symbols);
141    
142            // Add attributes to the link to control mouse over/out.
143            // Because the script is written before the <body> tag,
144            // there won't be any timing issues (such as cause
145            // bug #113893).
146    
147            link.addEventHandler(LinkEventType.MOUSE_OVER, (String) symbols.get("onMouseOverName"));
148            link.addEventHandler(LinkEventType.MOUSE_OUT, (String) symbols.get("onMouseOutName"));
149    
150            return imageName;
151        }
152    
153        public abstract IAsset getBlur();
154    
155        public abstract IAsset getDisabled();
156    
157        public abstract IAsset getFocus();
158    
159        public abstract IAsset getImage();
160    }