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 package org.apache.tapestry.dojo; 015 016 import org.apache.hivemind.util.Defense; 017 import org.apache.tapestry.*; 018 import org.apache.tapestry.html.Shell; 019 import org.apache.tapestry.json.JSONObject; 020 021 import java.util.Locale; 022 023 /** 024 * The default rendering delegate responseible for include the dojo sources in 025 * to the {@link Shell} component. 026 */ 027 public class AjaxShellDelegate implements IRender { 028 029 /** Client side debug log level. */ 030 public static final String BROWSER_LOG_DEBUG="DEBUG"; 031 /** Client side info log level. */ 032 public static final String BROWSER_LOG_INFO="INFO"; 033 /** Client side warning log level. */ 034 public static final String BROWSER_LOG_WARNING="WARNING"; 035 /** Client side error log level. */ 036 public static final String BROWSER_LOG_ERROR="ERROR"; 037 /** Client side critical log level. */ 038 public static final String BROWSER_LOG_CRITICAL="CRITICAL"; 039 040 private IAsset _dojoSource; 041 042 private IAsset _dojoFormSource; 043 044 private IAsset _dojoWidgetSource; 045 046 private IAsset _dojoPath; 047 048 private IAsset _tapestrySource; 049 050 private IAsset _tapestryPath; 051 052 private boolean _parseWidgets; 053 054 private String _browserLogLevel = BROWSER_LOG_WARNING; 055 056 private boolean _debug; 057 058 private String _debugContainerId; 059 060 private boolean _consoleEnabled; 061 062 private boolean _preventBackButtonFix; 063 064 private boolean _debugAtAllCosts; 065 066 /** 067 * {@inheritDoc} 068 */ 069 public void render(IMarkupWriter writer, IRequestCycle cycle) 070 { 071 // first configure dojo, has to happen before package include 072 073 JSONObject dojoConfig = new JSONObject(); 074 075 // Debugging configuration , debugAtAlCosts causes the individual 076 // .js files to included in the document head so that javascript errors 077 // are able to resolve to the context of the file instead of just "dojo.js" 078 079 dojoConfig.put("isDebug", _debug); 080 081 if (_debugAtAllCosts) 082 dojoConfig.put("debugAtAllCosts", _debugAtAllCosts); 083 if (_debugContainerId != null) 084 dojoConfig.put("debugContainerId", _debugContainerId); 085 086 IPage page = cycle.getPage(); 087 088 // The key to resolving everything out of the asset service 089 090 dojoConfig.put("baseRelativePath", _dojoPath.buildURL()); 091 092 if (page.hasFormComponents()) 093 { 094 dojoConfig.put("preventBackButtonFix", _preventBackButtonFix); 095 } 096 dojoConfig.put("parseWidgets", _parseWidgets); 097 098 // Supports setting up locale in dojo environment to match the requested page locale. 099 // (for things that use these settings, like DropdownDatePicker / date parsing / etc.. 100 101 Locale locale = cycle.getPage().getLocale(); 102 103 dojoConfig.put("locale", locale.getLanguage().toLowerCase() 104 + ((locale.getCountry() != null && locale.getCountry().trim().length() > 0) 105 ? "-" + locale.getCountry().toLowerCase() 106 : "")); 107 108 // Write the required script includes and dojo.requires 109 110 StringBuffer str = new StringBuffer("<script type=\"text/javascript\">"); 111 str.append("djConfig = ").append(dojoConfig.toString()) 112 .append(" </script>\n\n "); 113 114 // include the core dojo.js package 115 116 str.append("<script type=\"text/javascript\" src=\"") 117 .append(_dojoSource.buildURL()).append("\"></script>"); 118 119 if (page.hasFormComponents()) 120 { 121 str.append("<script type=\"text/javascript\" src=\"") 122 .append(_dojoFormSource.buildURL()).append("\"></script>"); 123 } 124 125 if (page.hasWidgets()) 126 { 127 str.append("<script type=\"text/javascript\" src=\"") 128 .append(_dojoWidgetSource.buildURL()).append("\"></script>"); 129 } 130 131 // configure basic dojo properties , logging includes 132 133 if (_debug) 134 { 135 String logRequire = _consoleEnabled ? "dojo.require(\"dojo.debug.console\");\n" 136 : "dojo.require(\"dojo.logging.Logger\");\n"; 137 138 str.append("\n<script type=\"text/javascript\">\n"); 139 str.append(logRequire) 140 .append("dojo.log.setLevel(dojo.log.getLevel(\"").append(_browserLogLevel) 141 .append("\"));\n") 142 .append("</script>"); 143 } 144 145 // module path registration to tapestry javascript sources 146 147 String tapestryUrl = _tapestryPath.buildURL(); 148 if (tapestryUrl.endsWith("/")) 149 { 150 tapestryUrl = tapestryUrl.substring(0, tapestryUrl.length() - 1); 151 } 152 153 str.append("\n<script type=\"text/javascript\">\n") 154 .append("dojo.registerModulePath(\"tapestry\", \"") 155 .append(tapestryUrl).append("\");\n"); 156 str.append("</script>\n"); 157 158 // include core tapestry.js package 159 160 str.append("<script type=\"text/javascript\" src=\"") 161 .append(_tapestrySource.buildURL()).append("\"></script>"); 162 163 // namespace registration 164 165 str.append("\n<script type=\"text/javascript\">\n"); 166 str.append("dojo.require(\"tapestry.namespace\");\n") 167 .append("tapestry.requestEncoding='").append(cycle.getEngine().getOutputEncoding()) 168 .append("';\n").append("</script>"); 169 170 writer.printRaw(str.toString()); 171 writer.println(); 172 } 173 174 /** 175 * Sets the dojo logging level. Similar to log4j style 176 * log levels. 177 * @param level The string constant for the level, valid values 178 * are: 179 * <p> 180 * <ul> 181 * <li>{@link #BROWSER_LOG_DEBUG}</li> 182 * <li>{@link #BROWSER_LOG_INFO}</li> 183 * <li>{@link #BROWSER_LOG_WARNING}</li> 184 * <li>{@link #BROWSER_LOG_ERROR}</li> 185 * <li>{@link #BROWSER_LOG_CRITICAL}</li> 186 * </ul> 187 * </p> 188 */ 189 public void setLogLevel(String level) 190 { 191 Defense.notNull("level", level); 192 193 _browserLogLevel = level; 194 } 195 196 /** 197 * Allows for turning browser debugging on/off. 198 * 199 * @param debug If false, no logging output will be written. 200 */ 201 public void setDebug(boolean debug) 202 { 203 _debug = debug; 204 } 205 206 /** 207 * Turns off deep context level javascript debugging mode for dojo. This means 208 * that exceptions/debug statements will show you line numbers from the actual 209 * javascript file that generated them instead of the normal default which is 210 * usually bootstrap.js . 211 * 212 * <p>The default value is false if not set.</p> 213 * 214 * <p> 215 * People should be wary of turning this on as it may cause problems 216 * under certain conditions, and you definitely don't ever want this 217 * on in production. 218 * </p> 219 * 220 * @param value If true deep debugging will be turned on. 221 */ 222 public void setDebugAtAllCosts(boolean value) 223 { 224 _debugAtAllCosts = value; 225 } 226 227 /** 228 * Sets the html element node id of the element you would like all browser 229 * debug content to go to. 230 * 231 * @param debugContainerId the debugContainerId to set 232 */ 233 public void setDebugContainerId(String debugContainerId) 234 { 235 _debugContainerId = debugContainerId; 236 } 237 238 /** 239 * Enables/disables the dojo.debug.console functionality which should redirect 240 * most logging messages to your browsers javascript console. (if it supports 241 * one). 242 * 243 * <p> 244 * The debug console is disabled by default. Currently known supported 245 * browsers are FireFox(having FireBug extension helps a great deal)/Opera/Safari. 246 * </p> 247 * 248 * @param enabled Whether or not the enable debug console. 249 */ 250 public void setConsoleEnabled(boolean enabled) 251 { 252 _consoleEnabled = enabled; 253 } 254 255 /** 256 * Sets the dojo preventBackButtonFix djConfig configuration. This should 257 * typically be avoided but is provided for flexibility. 258 * 259 * @param prevent 260 * Whether or not to prevent back button fix. 261 */ 262 public void setPreventBackButtonFix(boolean prevent) 263 { 264 _preventBackButtonFix = prevent; 265 } 266 267 /** 268 * Tells dojo whether or not to parse widgets by traversing the entire 269 * dom node of your document. It is highly reccomended that you keep this 270 * at its default value of false. 271 * 272 * @param parseWidgets the parseWidgets to set 273 */ 274 public void setParseWidgets(boolean parseWidgets) 275 { 276 _parseWidgets = parseWidgets; 277 } 278 279 /** 280 * Sets a valid path to the base dojo javascript installation 281 * directory. 282 * 283 * @param dojoSource 284 * Path to dojo source directory core "dojo.js" file. 285 */ 286 public void setDojoSource(IAsset dojoSource) 287 { 288 _dojoSource = dojoSource; 289 } 290 291 public void setDojoFormSource(IAsset formSource) 292 { 293 _dojoFormSource = formSource; 294 } 295 296 public void setDojoWidgetSource(IAsset widgetSource) 297 { 298 _dojoWidgetSource = widgetSource; 299 } 300 301 /** 302 * Sets the dojo baseRelativePath value. 303 * 304 * @param dojoPath 305 * The base path to dojo directory. 306 */ 307 public void setDojoPath(IAsset dojoPath) 308 { 309 _dojoPath = dojoPath; 310 } 311 312 /** 313 * Sets a valid base path to resolve tapestry core.js. 314 * 315 * @param tapestrySource 316 * Main tapestry core.js file. 317 */ 318 public void setTapestrySource(IAsset tapestrySource) 319 { 320 _tapestrySource = tapestrySource; 321 } 322 323 /** 324 * Sets the path to the tapestry javascript modules. (Needed for dojo to resolve the 325 * path to tapestry javascript, esp when overriding the default bundled dojo.) 326 * 327 * @param tapestryPath The path to tapestry. 328 */ 329 public void setTapestryPath(IAsset tapestryPath) 330 { 331 _tapestryPath = tapestryPath; 332 } 333 }