Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
AjaxShellDelegate |
|
| 1.9333333333333333;1.933 |
1 | // Copyright 2004, 2005 The Apache Software Foundation |
|
2 | // |
|
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
|
4 | // you may not use this file except in compliance with the License. |
|
5 | // You may obtain a copy of the License at |
|
6 | // |
|
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
|
8 | // |
|
9 | // Unless required by applicable law or agreed to in writing, software |
|
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
|
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
12 | // See the License for the specific language governing permissions and |
|
13 | // limitations under the License. |
|
14 | package org.apache.tapestry.dojo; |
|
15 | ||
16 | import org.apache.hivemind.util.Defense; |
|
17 | import org.apache.tapestry.*; |
|
18 | import org.apache.tapestry.html.Shell; |
|
19 | import org.apache.tapestry.json.JSONObject; |
|
20 | ||
21 | import java.util.Locale; |
|
22 | ||
23 | /** |
|
24 | * The default rendering delegate responseible for include the dojo sources in |
|
25 | * to the {@link Shell} component. |
|
26 | */ |
|
27 | 2 | public class AjaxShellDelegate implements IRender { |
28 | ||
29 | /** Client side debug log level. */ |
|
30 | public static final String BROWSER_LOG_DEBUG="DEBUG"; |
|
31 | /** Client side info log level. */ |
|
32 | public static final String BROWSER_LOG_INFO="INFO"; |
|
33 | /** Client side warning log level. */ |
|
34 | public static final String BROWSER_LOG_WARNING="WARNING"; |
|
35 | /** Client side error log level. */ |
|
36 | public static final String BROWSER_LOG_ERROR="ERROR"; |
|
37 | /** Client side critical log level. */ |
|
38 | public static final String BROWSER_LOG_CRITICAL="CRITICAL"; |
|
39 | ||
40 | 1 | private static final String SYSTEM_NEWLINE= (String)java.security.AccessController.doPrivileged( |
41 | new sun.security.action.GetPropertyAction("line.separator")); |
|
42 | ||
43 | private IAsset _dojoSource; |
|
44 | ||
45 | private IAsset _dojoFormSource; |
|
46 | ||
47 | private IAsset _dojoWidgetSource; |
|
48 | ||
49 | private IAsset _dojoPath; |
|
50 | ||
51 | private IAsset _tapestrySource; |
|
52 | ||
53 | private IAsset _tapestryPath; |
|
54 | ||
55 | private boolean _parseWidgets; |
|
56 | ||
57 | 2 | private String _browserLogLevel = BROWSER_LOG_WARNING; |
58 | ||
59 | private boolean _debug; |
|
60 | ||
61 | private String _debugContainerId; |
|
62 | ||
63 | private boolean _consoleEnabled; |
|
64 | ||
65 | private boolean _preventBackButtonFix; |
|
66 | ||
67 | private boolean _debugAtAllCosts; |
|
68 | ||
69 | /** Default list of pre-bundled dojo supported locales */ |
|
70 | 2 | protected String[] SUPPORTED_LOCALES = { "en-us", "de-de", "de", "en-gb", |
71 | "es-es", "es", "fr-fr", "fr", "zh-cn", |
|
72 | "zh-tw", "zh" , "it-it", "it", "ja-jp", |
|
73 | "ja", "ko-kr", "ko", "pt-br", "pt", "en", "xx"}; |
|
74 | ||
75 | /** |
|
76 | * {@inheritDoc} |
|
77 | */ |
|
78 | public void render(IMarkupWriter writer, IRequestCycle cycle) |
|
79 | { |
|
80 | // first configure dojo, has to happen before package include |
|
81 | ||
82 | 2 | JSONObject dojoConfig = new JSONObject(); |
83 | ||
84 | // Debugging configuration , debugAtAlCosts causes the individual |
|
85 | // .js files to included in the document head so that javascript errors |
|
86 | // are able to resolve to the context of the file instead of just "dojo.js" |
|
87 | ||
88 | 2 | if (_debug) |
89 | { |
|
90 | 1 | dojoConfig.put("isDebug", _debug); |
91 | } |
|
92 | ||
93 | 2 | if (_debugAtAllCosts) |
94 | 0 | dojoConfig.put("debugAtAllCosts", _debugAtAllCosts); |
95 | 2 | if (_debugContainerId != null) |
96 | 0 | dojoConfig.put("debugContainerId", _debugContainerId); |
97 | ||
98 | 2 | IPage page = cycle.getPage(); |
99 | ||
100 | // The key to resolving everything out of the asset service |
|
101 | ||
102 | 2 | dojoConfig.put("baseRelativePath", _dojoPath.buildURL()); |
103 | ||
104 | 2 | if (page.hasFormComponents()) |
105 | { |
|
106 | 0 | dojoConfig.put("preventBackButtonFix", _preventBackButtonFix); |
107 | } |
|
108 | 2 | dojoConfig.put("parseWidgets", _parseWidgets); |
109 | ||
110 | // Supports setting up locale in dojo environment to match the requested page locale. |
|
111 | // (for things that use these settings, like DropdownDatePicker / date parsing / etc.. |
|
112 | ||
113 | 2 | Locale locale = cycle.getPage().getLocale(); |
114 | ||
115 | 2 | String localeStr = locale.getLanguage().toLowerCase() |
116 | + ((locale.getCountry() != null && locale.getCountry().trim().length() > 0) |
|
117 | ? "-" + locale.getCountry().toLowerCase() |
|
118 | : ""); |
|
119 | ||
120 | 2 | if (isLocaleSupported(localeStr)) |
121 | { |
|
122 | 2 | dojoConfig.put("locale", localeStr); |
123 | } |
|
124 | ||
125 | // Write the required script includes and dojo.requires |
|
126 | ||
127 | 2 | StringBuffer str = new StringBuffer("<script type=\"text/javascript\">"); |
128 | 2 | str.append("djConfig = ").append(dojoConfig.toString()) |
129 | .append(" </script>") |
|
130 | .append(SYSTEM_NEWLINE).append(SYSTEM_NEWLINE); |
|
131 | ||
132 | // include the core dojo.js package |
|
133 | ||
134 | 2 | str.append("<script type=\"text/javascript\" src=\"") |
135 | .append(_dojoSource.buildURL()).append("\"></script>"); |
|
136 | ||
137 | 2 | if (page.hasFormComponents()) |
138 | { |
|
139 | 0 | str.append("<script type=\"text/javascript\" src=\"") |
140 | .append(_dojoFormSource.buildURL()).append("\"></script>"); |
|
141 | } |
|
142 | ||
143 | 2 | if (page.hasWidgets()) |
144 | { |
|
145 | 0 | str.append("<script type=\"text/javascript\" src=\"") |
146 | .append(_dojoWidgetSource.buildURL()).append("\"></script>"); |
|
147 | } |
|
148 | ||
149 | // configure basic dojo properties , logging includes |
|
150 | ||
151 | 2 | if (_debug) |
152 | { |
|
153 | 1 | String logRequire = _consoleEnabled ? "dojo.require(\"dojo.debug.console\");" + SYSTEM_NEWLINE |
154 | : "dojo.require(\"dojo.logging.Logger\");" + SYSTEM_NEWLINE; |
|
155 | ||
156 | 1 | str.append(SYSTEM_NEWLINE).append("<script type=\"text/javascript\">").append(SYSTEM_NEWLINE); |
157 | 1 | str.append(logRequire) |
158 | .append("dojo.log.setLevel(dojo.log.getLevel(\"").append(_browserLogLevel) |
|
159 | .append("\"));").append(SYSTEM_NEWLINE) |
|
160 | .append("</script>"); |
|
161 | } |
|
162 | ||
163 | // module path registration to tapestry javascript sources |
|
164 | ||
165 | 2 | String tapestryUrl = _tapestryPath.buildURL(); |
166 | 2 | if (tapestryUrl.endsWith("/")) |
167 | { |
|
168 | 0 | tapestryUrl = tapestryUrl.substring(0, tapestryUrl.length() - 1); |
169 | } |
|
170 | ||
171 | 2 | str.append(SYSTEM_NEWLINE).append("<script type=\"text/javascript\">").append(SYSTEM_NEWLINE) |
172 | .append("dojo.registerModulePath(\"tapestry\", \"") |
|
173 | .append(tapestryUrl).append("\");").append(SYSTEM_NEWLINE); |
|
174 | 2 | str.append("</script>").append(SYSTEM_NEWLINE); |
175 | ||
176 | // include core tapestry.js package |
|
177 | ||
178 | 2 | str.append("<script type=\"text/javascript\" src=\"") |
179 | .append(_tapestrySource.buildURL()).append("\"></script>"); |
|
180 | ||
181 | // namespace registration |
|
182 | ||
183 | 2 | str.append(SYSTEM_NEWLINE).append("<script type=\"text/javascript\">").append(SYSTEM_NEWLINE); |
184 | 2 | str.append("dojo.require(\"tapestry.namespace\");").append(SYSTEM_NEWLINE) |
185 | .append("tapestry.requestEncoding='") |
|
186 | .append(cycle.getEngine().getOutputEncoding()).append("';") |
|
187 | .append(SYSTEM_NEWLINE).append("</script>"); |
|
188 | ||
189 | 2 | writer.printRaw(str.toString()); |
190 | 2 | writer.println(); |
191 | 2 | } |
192 | ||
193 | /** |
|
194 | * Checks if the provided locale string matches one of the predefined {@link #SUPPORTED_LOCALES} |
|
195 | * in the dojo javascript library. |
|
196 | * |
|
197 | * @param locale |
|
198 | * The Dojo formatted locale string to check. |
|
199 | * |
|
200 | * @return True if locale is supported and ok to define in dojoConfig - false otherwise. |
|
201 | */ |
|
202 | protected boolean isLocaleSupported(String locale) |
|
203 | { |
|
204 | 2 | if (locale == null) |
205 | 0 | return false; |
206 | ||
207 | 5 | for (int i=0; i < SUPPORTED_LOCALES.length; i++) |
208 | { |
|
209 | 5 | if (locale.equals(SUPPORTED_LOCALES[i])) |
210 | 2 | return true; |
211 | } |
|
212 | ||
213 | 0 | return false; |
214 | } |
|
215 | ||
216 | /** |
|
217 | * Sets the dojo logging level. Similar to log4j style |
|
218 | * log levels. |
|
219 | * @param level The string constant for the level, valid values |
|
220 | * are: |
|
221 | * <p> |
|
222 | * <ul> |
|
223 | * <li>{@link #BROWSER_LOG_DEBUG}</li> |
|
224 | * <li>{@link #BROWSER_LOG_INFO}</li> |
|
225 | * <li>{@link #BROWSER_LOG_WARNING}</li> |
|
226 | * <li>{@link #BROWSER_LOG_ERROR}</li> |
|
227 | * <li>{@link #BROWSER_LOG_CRITICAL}</li> |
|
228 | * </ul> |
|
229 | * </p> |
|
230 | */ |
|
231 | public void setLogLevel(String level) |
|
232 | { |
|
233 | 1 | Defense.notNull("level", level); |
234 | ||
235 | 1 | _browserLogLevel = level; |
236 | 1 | } |
237 | ||
238 | /** |
|
239 | * Allows for turning browser debugging on/off. |
|
240 | * |
|
241 | * @param debug If false, no logging output will be written. |
|
242 | */ |
|
243 | public void setDebug(boolean debug) |
|
244 | { |
|
245 | 1 | _debug = debug; |
246 | 1 | } |
247 | ||
248 | /** |
|
249 | * Turns off deep context level javascript debugging mode for dojo. This means |
|
250 | * that exceptions/debug statements will show you line numbers from the actual |
|
251 | * javascript file that generated them instead of the normal default which is |
|
252 | * usually bootstrap.js . |
|
253 | * |
|
254 | * <p>The default value is false if not set.</p> |
|
255 | * |
|
256 | * <p> |
|
257 | * People should be wary of turning this on as it may cause problems |
|
258 | * under certain conditions, and you definitely don't ever want this |
|
259 | * on in production. |
|
260 | * </p> |
|
261 | * |
|
262 | * @param value If true deep debugging will be turned on. |
|
263 | */ |
|
264 | public void setDebugAtAllCosts(boolean value) |
|
265 | { |
|
266 | 0 | _debugAtAllCosts = value; |
267 | 0 | } |
268 | ||
269 | /** |
|
270 | * Sets the html element node id of the element you would like all browser |
|
271 | * debug content to go to. |
|
272 | * |
|
273 | * @param debugContainerId the debugContainerId to set |
|
274 | */ |
|
275 | public void setDebugContainerId(String debugContainerId) |
|
276 | { |
|
277 | 0 | _debugContainerId = debugContainerId; |
278 | 0 | } |
279 | ||
280 | /** |
|
281 | * Enables/disables the dojo.debug.console functionality which should redirect |
|
282 | * most logging messages to your browsers javascript console. (if it supports |
|
283 | * one). |
|
284 | * |
|
285 | * <p> |
|
286 | * The debug console is disabled by default. Currently known supported |
|
287 | * browsers are FireFox(having FireBug extension helps a great deal)/Opera/Safari. |
|
288 | * </p> |
|
289 | * |
|
290 | * @param enabled Whether or not the enable debug console. |
|
291 | */ |
|
292 | public void setConsoleEnabled(boolean enabled) |
|
293 | { |
|
294 | 1 | _consoleEnabled = enabled; |
295 | 1 | } |
296 | ||
297 | /** |
|
298 | * Sets the dojo preventBackButtonFix djConfig configuration. This should |
|
299 | * typically be avoided but is provided for flexibility. |
|
300 | * |
|
301 | * @param prevent |
|
302 | * Whether or not to prevent back button fix. |
|
303 | */ |
|
304 | public void setPreventBackButtonFix(boolean prevent) |
|
305 | { |
|
306 | 0 | _preventBackButtonFix = prevent; |
307 | 0 | } |
308 | ||
309 | /** |
|
310 | * Tells dojo whether or not to parse widgets by traversing the entire |
|
311 | * dom node of your document. It is highly reccomended that you keep this |
|
312 | * at its default value of false. |
|
313 | * |
|
314 | * @param parseWidgets the parseWidgets to set |
|
315 | */ |
|
316 | public void setParseWidgets(boolean parseWidgets) |
|
317 | { |
|
318 | 0 | _parseWidgets = parseWidgets; |
319 | 0 | } |
320 | ||
321 | /** |
|
322 | * Sets a valid path to the base dojo javascript installation |
|
323 | * directory. |
|
324 | * |
|
325 | * @param dojoSource |
|
326 | * Path to dojo source directory core "dojo.js" file. |
|
327 | */ |
|
328 | public void setDojoSource(IAsset dojoSource) |
|
329 | { |
|
330 | 2 | _dojoSource = dojoSource; |
331 | 2 | } |
332 | ||
333 | public void setDojoFormSource(IAsset formSource) |
|
334 | { |
|
335 | 0 | _dojoFormSource = formSource; |
336 | 0 | } |
337 | ||
338 | public void setDojoWidgetSource(IAsset widgetSource) |
|
339 | { |
|
340 | 0 | _dojoWidgetSource = widgetSource; |
341 | 0 | } |
342 | ||
343 | /** |
|
344 | * Sets the dojo baseRelativePath value. |
|
345 | * |
|
346 | * @param dojoPath |
|
347 | * The base path to dojo directory. |
|
348 | */ |
|
349 | public void setDojoPath(IAsset dojoPath) |
|
350 | { |
|
351 | 2 | _dojoPath = dojoPath; |
352 | 2 | } |
353 | ||
354 | /** |
|
355 | * Sets a valid base path to resolve tapestry core.js. |
|
356 | * |
|
357 | * @param tapestrySource |
|
358 | * Main tapestry core.js file. |
|
359 | */ |
|
360 | public void setTapestrySource(IAsset tapestrySource) |
|
361 | { |
|
362 | 2 | _tapestrySource = tapestrySource; |
363 | 2 | } |
364 | ||
365 | /** |
|
366 | * Sets the path to the tapestry javascript modules. (Needed for dojo to resolve the |
|
367 | * path to tapestry javascript, esp when overriding the default bundled dojo.) |
|
368 | * |
|
369 | * @param tapestryPath The path to tapestry. |
|
370 | */ |
|
371 | public void setTapestryPath(IAsset tapestryPath) |
|
372 | { |
|
373 | 2 | _tapestryPath = tapestryPath; |
374 | 2 | } |
375 | } |