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