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)
049        {
050            if (asset == null)
051                return null;
052    
053            return asset.buildURL();
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 mouseOverURL = null;
066            String mouseOutURL = null;
067            boolean dynamic = false;
068            String imageId = 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());
084    
085                if (imageURL == null)
086                    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,
128                ILinkComponent link, String mouseOverImageURL, String mouseOutImageURL)
129        {
130            String imageId = pageRenderSupport.getUniqueString(getId());
131            String preloadedMouseOverImageURL = pageRenderSupport
132                    .getPreloadedImageReference(mouseOverImageURL);
133            String preloadedMouseOutImageURL = pageRenderSupport
134                    .getPreloadedImageReference(mouseOutImageURL);
135    
136            Map symbols = new HashMap();
137    
138            symbols.put("imageId", imageId);
139            symbols.put("mouseOverImageURL", preloadedMouseOverImageURL);
140            symbols.put("mouseOutImageURL", preloadedMouseOutImageURL);
141    
142            getScript().execute(cycle, pageRenderSupport, symbols);
143    
144            // Add attributes to the link to control mouse over/out.
145            // Because the script is written before the <body> tag,
146            // there won't be any timing issues (such as cause
147            // bug #113893).
148    
149            link.addEventHandler(LinkEventType.MOUSE_OVER, (String) symbols.get("onMouseOverName"));
150            link.addEventHandler(LinkEventType.MOUSE_OUT, (String) symbols.get("onMouseOutName"));
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    }