001 package railo.runtime.tag; 002 003 import java.io.IOException; 004 import java.util.Iterator; 005 import java.util.LinkedHashMap; 006 import java.util.Map; 007 008 import railo.commons.lang.IDGenerator; 009 import railo.commons.lang.StringUtil; 010 import railo.runtime.exp.ApplicationException; 011 import railo.runtime.exp.ExpressionException; 012 import railo.runtime.exp.PageException; 013 import railo.runtime.ext.tag.BodyTagImpl; 014 import railo.runtime.functions.dynamicEvaluation.DE; 015 import railo.runtime.functions.string.JSStringFormat; 016 import railo.runtime.net.http.ReqRspUtil; 017 import railo.runtime.op.Caster; 018 import railo.runtime.op.Decision; 019 import railo.runtime.tag.util.DeprecatedUtil; 020 import railo.runtime.type.KeyImpl; 021 import railo.runtime.type.Struct; 022 import railo.runtime.type.StructImpl; 023 024 /** 025 * implementation of the form tag 026 */ 027 public final class Form extends BodyTagImpl { 028 029 public static final int FORMAT_HTML = 0; 030 public static final int FORMAT_FLASH = 1; 031 public static final int FORMAT_XML = 2; 032 private static final String DEFAULT_ARCHIVE = "/railo-context/railo-applet.cfm"; 033 034 private static final int WMODE_WINDOW = 0; 035 private static final int WMODE_TRANSPARENT = 1; 036 private static final int WMODE_OPAQUE = 2; 037 038 039 //private static int _count=0; 040 private int count=0; 041 private String name; 042 private String action; 043 private boolean preserveData; 044 private String onsubmit; 045 private String onreset; 046 private String onload; 047 private String passthrough; 048 private String method="post"; 049 private String scriptSrc; 050 051 private int format=FORMAT_HTML; 052 053 054 055 private Struct attributes=new StructImpl(); 056 private Map inputs=new LinkedHashMap(); 057 private String strSkin; 058 private String archive=null; 059 private String codebase=null; // TODO muss einen wert haben -> /railo - context/classes/cf-j2re-win.cab.cfm 060 private String height="100%"; 061 private String width="100%"; 062 private boolean preloader=true; 063 private int timeout=0; 064 private int wMode=WMODE_WINDOW; 065 private boolean accessible=false; 066 067 068 /** 069 * @see javax.servlet.jsp.tagext.Tag#release() 070 */ 071 public void release() { 072 super.release(); 073 name=null; 074 action=null; 075 preserveData=false; 076 attributes.clear(); 077 onsubmit=null; 078 onreset=null; 079 onload=null; 080 passthrough=null; 081 method="post"; 082 scriptSrc=null; 083 strSkin=null; 084 archive=null; 085 codebase=null; 086 height="100%"; 087 width="100%"; 088 preloader=true; 089 timeout=0; 090 wMode=WMODE_WINDOW; 091 accessible=false; 092 093 inputs.clear(); 094 } 095 096 097 /** 098 * @param enablecab The enablecab to set. 099 * @throws ApplicationException 100 */ 101 public void setEnablecab(boolean enablecab) { 102 DeprecatedUtil.tagAttribute(pageContext,"Form", "enablecab"); 103 104 } 105 /** 106 * @param method The method to set. 107 * @throws ApplicationException 108 */ 109 public void setMethod(String method) throws ApplicationException { 110 method=method.trim().toLowerCase(); 111 if(method.equals("get") || method.equals("post")) 112 this.method = method; 113 else 114 throw new ApplicationException("invalid value for attribute method from tag form, attribute can have value [get,post] but now is ["+method+"]"); 115 } 116 117 118 /** 119 * @param format the format to set 120 * @throws ApplicationException 121 */ 122 public void setFormat(String strFormat) throws ApplicationException { 123 strFormat=strFormat.trim().toLowerCase(); 124 125 if("html".equals(strFormat)) format=FORMAT_HTML; 126 else if("xml".equals(strFormat)) format=FORMAT_XML; 127 else if("flash".equals(strFormat)) format=FORMAT_FLASH; 128 129 else throw new ApplicationException("invalid value ["+strFormat+"] for attribute format, for this attribute only the following values are supported " + 130 "[xml, html, flash]"); 131 132 if(format!=FORMAT_HTML) 133 throw new ApplicationException("format ["+strFormat+"] is not supported, only the following formats are supported [html]"); 134 // TODO support other formats 135 } 136 137 /** 138 * @param skin The skin to set. 139 */ 140 public void setSkin(String strSkin) { 141 this.strSkin=strSkin; 142 } 143 144 /** 145 * @param action The action to set. 146 */ 147 public void setAction(String action) { 148 this.action = action; 149 } 150 151 /** 152 * @param scriptSrc The scriptSrc to set. 153 */ 154 public void setScriptsrc(String scriptSrc) { 155 this.scriptSrc = scriptSrc; 156 } 157 158 /** 159 * @param archive The archive to set. 160 * @throws ApplicationException 161 */ 162 public void setArchive(String archive) { 163 archive=archive.trim().toLowerCase().replace('\\', '/'); 164 if(!StringUtil.startsWith(archive, '/')) archive="/"+archive; 165 this.archive = archive; 166 } 167 /** 168 * @param codebase The codebase to set. 169 * @throws ApplicationException 170 */ 171 public void setCodebase(String codebase) { 172 this.codebase = codebase; 173 } 174 /** 175 * @param cssclass The cssclass to set. 176 */ 177 public void setClass(String cssclass) { 178 attributes.setEL("class",cssclass); 179 } 180 /** 181 * @param cssstyle The cssstyle to set. 182 */ 183 public void setStyle(String cssstyle) { 184 attributes.setEL("style",cssstyle); 185 } 186 /** 187 * @param enctype The enctype to set. 188 */ 189 public void setEnctype(String enctype) { 190 attributes.setEL("enctype",enctype); 191 } 192 /** 193 * @param id The id to set. 194 */ 195 public void setId(String id) { 196 attributes.setEL("id",id); 197 } 198 199 public void setAccept(String accept) { 200 attributes.setEL("accept",accept); 201 } 202 203 public void setAcceptcharset(String accept_charset) { 204 attributes.setEL("accept-charset",accept_charset); 205 } 206 207 public void setAccept_charset(String accept_charset) { 208 attributes.setEL("accept-charset",accept_charset); 209 } 210 /** 211 * @param name The name to set. 212 */ 213 public void setName(String name) { 214 this.name=name; 215 } 216 /** 217 * @param onreset The onreset to set. 218 */ 219 public void setOnreset(String onreset) { 220 this.onreset=onreset; 221 } 222 223 /** 224 * @param onreset The onreset to set. 225 */ 226 public void setOnload(String onload) { 227 this.onload=onload; 228 } 229 230 /** 231 * @param onsubmit The onsubmit to set. 232 */ 233 public void setOnsubmit(String onsubmit) { 234 this.onsubmit = onsubmit; 235 } 236 237 public void setOnclick(String onclick) { 238 attributes.setEL("onclick",onclick); 239 } 240 241 public void setOndblclick(String ondblclick) { 242 attributes.setEL("ondblclick",ondblclick); 243 } 244 245 public void setOnmousedown(String onmousedown) { 246 attributes.setEL("onmousedown",onmousedown); 247 } 248 249 public void setOnmouseup(String onmouseup) { 250 attributes.setEL("onmouseup",onmouseup); 251 } 252 253 public void setOnmouseover(String onmouseover) { 254 attributes.setEL("onmouseover",onmouseover); 255 } 256 257 public void setOnmousemove(String onmousemove) { 258 attributes.setEL("onmousemove",onmousemove); 259 } 260 261 public void setOnmouseout(String onmouseout) { 262 attributes.setEL("onmouseout",onmouseout); 263 } 264 265 public void setOnkeypress(String onkeypress) { 266 attributes.setEL("onkeypress",onkeypress); 267 } 268 269 public void setOnkeydown(String onkeydown) { 270 attributes.setEL("onkeydown",onkeydown); 271 } 272 273 public void setOnkeyup(String onkeyup) { 274 attributes.setEL("onkeyup",onkeyup); 275 } 276 277 /** 278 * @param passthrough The passthrough to set. 279 * @throws PageException 280 */ 281 public void setPassthrough(Object passthrough) throws PageException { 282 if(passthrough instanceof Struct) { 283 Struct sct = (Struct) passthrough; 284 railo.runtime.type.Collection.Key[] keys=sct.keys(); 285 railo.runtime.type.Collection.Key key; 286 for(int i=0;i<keys.length;i++) { 287 key=keys[i]; 288 attributes.setEL(key,sct.get(key,null)); 289 } 290 } 291 else this.passthrough = Caster.toString(passthrough); 292 } 293 /** 294 * @param preserveData The preserveData to set. 295 * @throws ApplicationException 296 */ 297 public void setPreservedata(boolean preserveData) throws ApplicationException { 298 //this.preserveData = preserveData; 299 if(preserveData)throw new ApplicationException("attribute preserveData for tag form is not supported at the moment"); 300 } 301 /** 302 * @param target The target to set. 303 */ 304 public void setTarget(String target) { 305 attributes.setEL("target",target); 306 } 307 308 public void setTitle(String title) { 309 attributes.setEL("title",title); 310 } 311 312 public void setDir(String dir) { 313 attributes.setEL("dir",dir); 314 } 315 316 public void setLang(String lang) { 317 attributes.setEL("lang",lang); 318 } 319 320 /** 321 * @param height the height to set 322 */ 323 public void setHeight(String height) { 324 this.height=height; 325 } 326 327 /** 328 * @param width the width to set 329 */ 330 public void setWidth(String width) { 331 this.width=width; 332 } 333 334 /** 335 * @param preloader the preloader to set 336 */ 337 public void setPreloader(boolean preloader) { 338 this.preloader=preloader; 339 } 340 341 /** 342 * @param timeout the timeout to set 343 */ 344 public void setTimeout(double timeout) { 345 this.timeout=(int)timeout; 346 } 347 348 /** 349 * @param strWMode the wmode to set 350 * @throws ApplicationException 351 */ 352 public void setWmode(String strWMode) throws ApplicationException { 353 strWMode=strWMode.toLowerCase().trim(); 354 if("window".equals(strWMode)) wMode=WMODE_WINDOW; 355 else if("transparent".equals(strWMode)) wMode=WMODE_TRANSPARENT; 356 else if("opaque".equals(strWMode)) wMode=WMODE_OPAQUE; 357 358 else throw new ApplicationException("invalid value ["+strWMode+"] for attribute wmode, for this attribute only the following values are supported " + 359 "[window, transparent, opaque]"); 360 } 361 362 /** 363 * @param strWMode the wmode to set 364 */ 365 public void setAccessible(boolean accessible) { 366 this.accessible=accessible; 367 } 368 369 /** 370 * @throws PageException 371 * @see javax.servlet.jsp.tagext.Tag#doStartTag() 372 */ 373 public int doStartTag() throws PageException { 374 375 try { 376 return _doStartTag(); 377 } 378 catch (IOException e) { 379 throw Caster.toPageException(e); 380 } 381 } 382 private int _doStartTag() throws PageException, IOException { 383 String contextPath = pageContext. getHttpServletRequest().getContextPath(); 384 if(contextPath==null) contextPath=""; 385 if(archive==null) { 386 archive=contextPath+DEFAULT_ARCHIVE; 387 } 388 count=IDGenerator.intId(); 389 390 if(name==null) { 391 name="CFForm_"+count; 392 } 393 attributes.setEL(KeyImpl.NAME,name); 394 395 if(action==null) action=ReqRspUtil.self(pageContext. getHttpServletRequest()); 396 attributes.setEL(KeyImpl.ACTION,action); 397 398 String suffix=StringUtil.isEmpty(name)?""+count:StringUtil.toVariableName(name); 399 String funcName="railo_form_"+count; 400 401 String checkName="_CF_check"+suffix; 402 String resetName="_CF_reset"+suffix; 403 String loadName="_CF_load"+suffix; 404 405 406 407 boolean hasListener=false; 408 if(onsubmit==null) attributes.setEL("onsubmit","return "+funcName+".check();"); 409 else { 410 attributes.setEL("onsubmit","return "+checkName+"();"); 411 hasListener=true; 412 } 413 if(onreset!=null) { 414 attributes.setEL("onreset",resetName+"();"); 415 hasListener=true; 416 } 417 if(onload!=null) { 418 attributes.setEL("onload",loadName+"();"); 419 hasListener=true; 420 } 421 422 if(scriptSrc==null)scriptSrc=contextPath+"/railo-context/form.cfm"; 423 attributes.setEL("method",method); 424 425 pageContext.forceWrite("<script language = \"JavaScript\" type=\"text/javascript\" src=\""+scriptSrc+"\"></script>"); 426 //if(hasListener) { 427 pageContext.forceWrite("<script language = \"JavaScript\" type=\"text/javascript\">\n"); 428 if(onsubmit!=null)pageContext.forceWrite("function "+checkName+"() { if("+funcName+".check()){"+onsubmit+"\nreturn true;}else {return false;}}\n"); 429 else pageContext.forceWrite("function "+checkName+"() { return "+funcName+".check();}\n"); 430 431 432 if(onreset!=null)pageContext.forceWrite("function "+resetName+"() {"+onreset+"\n}\n"); 433 if(onload!=null)pageContext.forceWrite("function "+loadName+"() {"+onload+"\n}\n"); 434 pageContext.forceWrite("\n</script>"); 435 436 //} 437 pageContext.forceWrite("<form"); 438 439 railo.runtime.type.Collection.Key[] keys = attributes.keys(); 440 railo.runtime.type.Collection.Key key; 441 for(int i=0;i<keys.length;i++) { 442 key = keys[i]; 443 pageContext.forceWrite(" "); 444 pageContext.forceWrite(key.getString()); 445 pageContext.forceWrite("="); 446 pageContext.forceWrite(de(Caster.toString(attributes.get(key,null)))); 447 448 } 449 450 if(passthrough!=null) { 451 pageContext.forceWrite(" "); 452 pageContext.forceWrite(passthrough); 453 } 454 pageContext.forceWrite(">"); 455 456 return EVAL_BODY_INCLUDE; 457 } 458 459 /** 460 * @throws ExpressionException 461 * @see javax.servlet.jsp.tagext.Tag#doEndTag() 462 */ 463 public int doEndTag() throws PageException { 464 String funcName="railo_form_"+count; 465 try { 466 pageContext.forceWrite("</form><!-- name:"+name+" --><script>\n"); 467 pageContext.forceWrite(funcName+"=new RailoForms("+js(name)+");\n"); 468 Iterator it = inputs.keySet().iterator(); 469 while(it.hasNext()) { 470 InputBean input=(InputBean) inputs.get(it.next()); 471 472 pageContext.forceWrite(funcName+".addInput("+js(input.getName())+","+input.isRequired()+ 473 ","+input.getType()+","+input.getValidate()+ 474 ","+(input.getPattern())+","+js(input.getMessage())+ 475 ","+js(input.getOnError())+","+js(input.getOnValidate())+ 476 ","+range(input.getRangeMin())+","+range(input.getRangeMax())+ 477 ","+(input.getMaxLength())+ 478 ");\n"); 479 } 480 pageContext.forceWrite("</script>"); 481 } 482 catch (IOException e) { 483 throw Caster.toPageException(e); 484 } 485 return EVAL_PAGE; 486 } 487 488 private String range(double range) { 489 if(!Decision.isValid(range)) return "null"; 490 return Caster.toString(range); 491 } 492 493 494 private String de(String str) { 495 try { 496 return DE.call(pageContext,str); 497 } catch (ExpressionException e) { 498 return "\"\""; 499 } 500 } 501 private String js(String str) { 502 if(str==null) return "null"; 503 return "'"+JSStringFormat.call(pageContext,str)+"'"; 504 } 505 506 507 /** 508 * @param input 509 * @throws ApplicationException 510 */ 511 public void setInput(InputBean input) throws ApplicationException { 512 if(input.getType()==Input.TYPE_TEXT || input.getType()==Input.TYPE_PASSWORD) { 513 InputBean i=(InputBean)inputs.get(input.getName().toLowerCase()); 514 if(i!=null && (i.getType()==Input.TYPE_TEXT || i.getType()==Input.TYPE_PASSWORD)) { 515 throw new ApplicationException("duplicate input field ["+i.getName()+"] for form","a text or password field must be unique"); 516 } 517 } 518 inputs.put(input.getName().toLowerCase(),input); 519 } 520 521 /** 522 * @return Returns the name. 523 */ 524 public String getName() { 525 return name; 526 } 527 /** 528 * @return Returns the onsubmit. 529 */ 530 public String getOnsubmit() { 531 return onsubmit; 532 } 533 534 public int getFormat() { 535 return format; 536 } 537 538 539 public String getArchive() { 540 return archive; 541 } 542 543 544 public String getCodebase() { 545 return codebase; 546 } 547 }