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