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
015package org.apache.tapestry.html;
016
017import org.apache.hivemind.Resource;
018import org.apache.tapestry.AbstractComponent;
019import org.apache.tapestry.IMarkupWriter;
020import org.apache.tapestry.IRequestCycle;
021import org.apache.tapestry.PageRenderSupport;
022import org.apache.tapestry.TapestryUtils;
023import org.apache.tapestry.asset.AssetFactory;
024import org.apache.tapestry.util.PageRenderSupportImpl;
025import 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
036public 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}