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.Resource;
018    import org.apache.tapestry.AbstractComponent;
019    import org.apache.tapestry.IMarkupWriter;
020    import org.apache.tapestry.IRequestCycle;
021    import org.apache.tapestry.PageRenderSupport;
022    import org.apache.tapestry.TapestryUtils;
023    import org.apache.tapestry.asset.AssetFactory;
024    import org.apache.tapestry.util.PageRenderSupportImpl;
025    import org.apache.tapestry.web.WebResponse;
026    
027    /**
028     * The body of a Tapestry page. This is used since it allows components on the page access to an
029     * initialization script (that is written the start, just inside the <body> tag). This is
030     * currently used by {@link Rollover}and {@link Script}components. [ <a
031     * href="../../../../../ComponentReference/Body.html">Component Reference </a>]
032     * 
033     * @author Howard Lewis Ship
034     */
035    
036    public abstract class Body extends AbstractComponent implements PageRenderSupport
037    {
038        private PageRenderSupportImpl _pageRenderSupport;
039    
040        /**
041         * Adds to the script an initialization for the named variable as an Image(), to the given URL.
042         * <p>
043         * Returns a reference, a string that can be used to represent the preloaded image in a
044         * JavaScript function.
045         * 
046         * @since 1.0.2
047         */
048    
049        public String getPreloadedImageReference(String URL)
050        {
051            return _pageRenderSupport.getPreloadedImageReference(URL);
052        }
053    
054        /**
055         * Adds other initialization, in the form of additional JavaScript code to execute from the
056         * &lt;body&gt;'s <code>onLoad</code> event handler. The caller is responsible for adding a
057         * semicolon (statement terminator). This method will add a newline after the script.
058         */
059    
060        public void addInitializationScript(String script)
061        {
062            _pageRenderSupport.addInitializationScript(script);
063        }
064    
065        /**
066         * Adds additional scripting code to the page. This code will be added to a large block of
067         * scripting code at the top of the page (i.e., the before the &lt;body&gt; tag).
068         * <p>
069         * This is typically used to add some form of JavaScript event handler to a page. For example,
070         * the {@link Rollover}component makes use of this.
071         * <p>
072         * Another way this is invoked is by using the {@link Script}component.
073         * <p>
074         * The string will be added, as-is, within the &lt;script&gt; block generated by this
075         * <code>Body</code> component. The script should <em>not</em> contain HTML comments, those
076         * will be supplied by this Body component.
077         * <p>
078         * A frequent use is to add an initialization function using this method, then cause it to be
079         * executed using {@link #addInitializationScript(String)}.
080         */
081    
082        public void addBodyScript(String script)
083        {
084            _pageRenderSupport.addBodyScript(script);
085        }
086    
087        /**
088         * Used to include a script from an outside URL (the scriptLocation is a URL, probably obtained
089         * from an asset. This adds an &lt;script src="..."&gt; tag before the main &lt;script&gt; tag.
090         * The Body component ensures that each URL is included only once.
091         * 
092         * @since 1.0.5
093         */
094    
095        public void addExternalScript(Resource scriptLocation)
096        {
097            _pageRenderSupport.addExternalScript(scriptLocation);
098        }
099    
100        /**
101         * Retrieves the <code>Body</code> that was stored into the request cycle. This allows
102         * components wrapped by the <code>Body</code> to locate it and access the services it
103         * provides.
104         * 
105         * @deprecated To be removed in 4.1. Use
106         *             {@link org.apache.tapestry.TapestryUtils#getPageRenderSupport(IRequestCycle)}
107         *             instead.
108         */
109    
110        public static Body get(IRequestCycle cycle)
111        {
112            return (Body) TapestryUtils.getOptionalPageRenderSupport(cycle);
113        }
114    
115        protected void prepareForRender(IRequestCycle cycle)
116        {
117            super.prepareForRender(cycle);
118    
119            _pageRenderSupport = new PageRenderSupportImpl(getAssetFactory(), getResponse()
120                    .getNamespace(), getLocation());
121        }
122    
123        protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
124        {
125            TapestryUtils.storePageRenderSupport(cycle, this);
126    
127            IMarkupWriter nested = writer.getNestedWriter();
128    
129            renderBody(nested, cycle);
130    
131            // Start the body tag.
132            writer.println();
133            writer.begin(getElement());
134            renderInformalParameters(writer, cycle);
135    
136            writer.println();
137    
138            // Write the page's scripting. This is included scripts
139            // and dynamic JavaScript.
140    
141            _pageRenderSupport.writeBodyScript(writer, cycle);
142    
143            // Close the nested writer, which dumps its buffered content
144            // into its parent.
145    
146            nested.close();
147    
148            // Any initialization should go at the very end of the document
149            // just before the close body tag. Older version of Tapestry
150            // would create a window.onload event handler, but this is better
151            // (it doesn't have to wait for external images to load).
152    
153            _pageRenderSupport.writeInitializationScript(writer);
154    
155            writer.end(); // <body>
156        }
157    
158        protected void cleanupAfterRender(IRequestCycle cycle)
159        {
160            super.cleanupAfterRender(cycle);
161    
162            _pageRenderSupport = null;
163    
164            TapestryUtils.removePageRenderSupport(cycle);
165        }
166    
167        /**
168         * Parameter.
169         */
170        public abstract String getElement();
171    
172        /**
173         * Injected
174         * 
175         * @since 4.0
176         */
177        public abstract AssetFactory getAssetFactory();
178    
179        /**
180         * Injected
181         * 
182         * @since 4.0
183         */
184    
185        public abstract WebResponse getResponse();
186    
187        /** @since 3.0 */
188    
189        public String getUniqueString(String baseValue)
190        {
191            return _pageRenderSupport.getUniqueString(baseValue);
192        }
193    
194    }