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 * <body>'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 <body> 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 <script> 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 <script src="..."> tag before the main <script> 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 }