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