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