package railo.runtime.tag; import java.io.IOException; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import railo.commons.lang.IDGenerator; import railo.commons.lang.StringUtil; import railo.runtime.exp.ApplicationException; import railo.runtime.exp.ExpressionException; import railo.runtime.exp.PageException; import railo.runtime.ext.tag.BodyTagImpl; import railo.runtime.functions.dynamicEvaluation.DE; import railo.runtime.functions.string.JSStringFormat; import railo.runtime.net.http.ReqRspUtil; import railo.runtime.op.Caster; import railo.runtime.op.Decision; import railo.runtime.tag.util.DeprecatedUtil; import railo.runtime.type.Collection.Key; import railo.runtime.type.Struct; import railo.runtime.type.StructImpl; import railo.runtime.type.util.KeyConstants; /** * implementation of the form tag */ public final class Form extends BodyTagImpl { public static final int FORMAT_HTML = 0; public static final int FORMAT_FLASH = 1; public static final int FORMAT_XML = 2; private static final String DEFAULT_ARCHIVE = "/railo-context/railo-applet.cfm"; private static final int WMODE_WINDOW = 0; private static final int WMODE_TRANSPARENT = 1; private static final int WMODE_OPAQUE = 2; //private static int _count=0; private int count=0; private String name; private String action; private boolean preserveData; private String onsubmit; private String onreset; private String onload; private String passthrough; private String method="post"; private String scriptSrc; private int format=FORMAT_HTML; private Struct attributes=new StructImpl(); private Map inputs=new LinkedHashMap(); private String strSkin; private String archive=null; private String codebase=null; // TODO muss einen wert haben -> /railo - context/classes/cf-j2re-win.cab.cfm private String height="100%"; private String width="100%"; private boolean preloader=true; private int timeout=0; private int wMode=WMODE_WINDOW; private boolean accessible=false; private String onError; @Override public void release() { super.release(); name=null; action=null; preserveData=false; attributes.clear(); onsubmit=null; onreset=null; onload=null; passthrough=null; method="post"; scriptSrc=null; strSkin=null; archive=null; codebase=null; height="100%"; width="100%"; preloader=true; timeout=0; wMode=WMODE_WINDOW; accessible=false; onError=null; inputs.clear(); } /** * @param enablecab The enablecab to set. * @throws ApplicationException */ public void setEnablecab(boolean enablecab) { DeprecatedUtil.tagAttribute(pageContext,"Form", "enablecab"); } /** * @param method The method to set. * @throws ApplicationException */ public void setMethod(String method) throws ApplicationException { method=method.trim().toLowerCase(); if(method.equals("get") || method.equals("post")) this.method = method; else throw new ApplicationException("invalid value for attribute method from tag form, attribute can have value [get,post] but now is ["+method+"]"); } /** * @param format the format to set * @throws ApplicationException */ public void setFormat(String strFormat) throws ApplicationException { strFormat=strFormat.trim().toLowerCase(); if("html".equals(strFormat)) format=FORMAT_HTML; else if("xml".equals(strFormat)) format=FORMAT_XML; else if("flash".equals(strFormat)) format=FORMAT_FLASH; else throw new ApplicationException("invalid value ["+strFormat+"] for attribute format, for this attribute only the following values are supported " + "[xml, html, flash]"); if(format!=FORMAT_HTML) throw new ApplicationException("format ["+strFormat+"] is not supported, only the following formats are supported [html]"); // TODO support other formats } /** * @param skin The skin to set. */ public void setSkin(String strSkin) { this.strSkin=strSkin; } /** * @param action The action to set. */ public void setAction(String action) { this.action = action; } /** * @param scriptSrc The scriptSrc to set. */ public void setScriptsrc(String scriptSrc) { this.scriptSrc = scriptSrc; } /** * @param archive The archive to set. * @throws ApplicationException */ public void setArchive(String archive) { archive=archive.trim().toLowerCase().replace('\\', '/'); if(!StringUtil.startsWith(archive, '/')) archive="/"+archive; this.archive = archive; } /** * @param codebase The codebase to set. * @throws ApplicationException */ public void setCodebase(String codebase) { this.codebase = codebase; } /** * @param cssclass The cssclass to set. */ public void setClass(String cssclass) { attributes.setEL("class",cssclass); } /** * @param cssstyle The cssstyle to set. */ public void setStyle(String cssstyle) { attributes.setEL("style",cssstyle); } /** * @param enctype The enctype to set. */ public void setEnctype(String enctype) { attributes.setEL("enctype",enctype); } /** * @param id The id to set. */ public void setId(String id) { attributes.setEL("id",id); } public void setAccept(String accept) { attributes.setEL("accept",accept); } public void setAcceptcharset(String accept_charset) { attributes.setEL("accept-charset",accept_charset); } public void setAccept_charset(String accept_charset) { attributes.setEL("accept-charset",accept_charset); } /** * @param name The name to set. * @throws ApplicationException */ public void setName(String name) throws ApplicationException { this.name=name; checkName(name); } private static void checkName(String name) throws ApplicationException { if(name.length()==0)return; int len=name.length(); for(int pos=0;pos<len;pos++) { char c=name.charAt(pos); if((c>='a' && c<='z')||(c>='A' && c<='Z')||(c>='0' && c<='9')||(c=='_')||(c=='-')||(c==':')||(c=='.')) continue; throw new ApplicationException("value of attribute name ["+name+"] is invalid, only the following characters are allowed [a-z,A-Z,0-9,-,_,:,.]"); } } /** * @param onreset The onreset to set. */ public void setOnreset(String onreset) { this.onreset=onreset; } /** * @param onreset The onreset to set. */ public void setOnload(String onload) { this.onload=onload; } /** * @param onsubmit The onsubmit to set. */ public void setOnsubmit(String onsubmit) { this.onsubmit = onsubmit; } public void setOnerror(String onError) { this.onError=onError; } public void setOnclick(String onclick) { attributes.setEL("onclick",onclick); } public void setOndblclick(String ondblclick) { attributes.setEL("ondblclick",ondblclick); } public void setOnmousedown(String onmousedown) { attributes.setEL("onmousedown",onmousedown); } public void setOnmouseup(String onmouseup) { attributes.setEL("onmouseup",onmouseup); } public void setOnmouseover(String onmouseover) { attributes.setEL("onmouseover",onmouseover); } public void setOnmousemove(String onmousemove) { attributes.setEL("onmousemove",onmousemove); } public void setOnmouseout(String onmouseout) { attributes.setEL("onmouseout",onmouseout); } public void setOnkeypress(String onkeypress) { attributes.setEL("onkeypress",onkeypress); } public void setOnkeydown(String onkeydown) { attributes.setEL("onkeydown",onkeydown); } public void setOnkeyup(String onkeyup) { attributes.setEL("onkeyup",onkeyup); } /** * @param passthrough The passthrough to set. * @throws PageException */ public void setPassthrough(Object passthrough) throws PageException { if(passthrough instanceof Struct) { Struct sct = (Struct) passthrough; //railo.runtime.type.Collection.Key[] keys=sct.keys(); //railo.runtime.type.Collection.Key key; Iterator<Entry<Key, Object>> it = sct.entryIterator(); Entry<Key, Object> e; while(it.hasNext()) { e = it.next(); attributes.setEL(e.getKey(),e.getValue()); } } else this.passthrough = Caster.toString(passthrough); } /** * @param preserveData The preserveData to set. * @throws ApplicationException */ public void setPreservedata(boolean preserveData) throws ApplicationException { //this.preserveData = preserveData; if(preserveData)throw new ApplicationException("attribute preserveData for tag form is not supported at the moment"); } /** * @param target The target to set. */ public void setTarget(String target) { attributes.setEL("target",target); } public void setTitle(String title) { attributes.setEL("title",title); } public void setDir(String dir) { attributes.setEL("dir",dir); } public void setLang(String lang) { attributes.setEL("lang",lang); } /** * @param height the height to set */ public void setHeight(String height) { this.height=height; } /** * @param width the width to set */ public void setWidth(String width) { this.width=width; } /** * @param preloader the preloader to set */ public void setPreloader(boolean preloader) { this.preloader=preloader; } /** * @param timeout the timeout to set */ public void setTimeout(double timeout) { this.timeout=(int)timeout; } /** * @param strWMode the wmode to set * @throws ApplicationException */ public void setWmode(String strWMode) throws ApplicationException { strWMode=strWMode.toLowerCase().trim(); if("window".equals(strWMode)) wMode=WMODE_WINDOW; else if("transparent".equals(strWMode)) wMode=WMODE_TRANSPARENT; else if("opaque".equals(strWMode)) wMode=WMODE_OPAQUE; else throw new ApplicationException("invalid value ["+strWMode+"] for attribute wmode, for this attribute only the following values are supported " + "[window, transparent, opaque]"); } /** * @param strWMode the wmode to set */ public void setAccessible(boolean accessible) { this.accessible=accessible; } @Override public int doStartTag() throws PageException { try { return _doStartTag(); } catch (IOException e) { throw Caster.toPageException(e); } } private int _doStartTag() throws PageException, IOException { String contextPath = pageContext. getHttpServletRequest().getContextPath(); if(contextPath==null) contextPath=""; if(archive==null) { archive=contextPath+DEFAULT_ARCHIVE; } count=IDGenerator.intId(); if(name==null) { name="CFForm_"+count; } attributes.setEL(KeyConstants._name,name); if(action==null) action=ReqRspUtil.self(pageContext. getHttpServletRequest()); attributes.setEL(KeyConstants._action,action); String suffix=StringUtil.isEmpty(name)?""+count:StringUtil.toVariableName(name); String funcName="railo_form_"+count; String checkName="_CF_check"+suffix; String resetName="_CF_reset"+suffix; String loadName="_CF_load"+suffix; //boolean hasListener=false; if(onsubmit==null) attributes.setEL("onsubmit","return "+funcName+".check();"); else { attributes.setEL("onsubmit","return "+checkName+"();"); //hasListener=true; } if(onreset!=null) { attributes.setEL("onreset",resetName+"();"); //hasListener=true; } if(onload!=null) { attributes.setEL("onload",loadName+"();"); //hasListener=true; } if(scriptSrc==null)scriptSrc=contextPath+"/railo-context/form.cfm"; attributes.setEL("method",method); pageContext.forceWrite("<script language = \"JavaScript\" type=\"text/javascript\" src=\""+scriptSrc+"\"></script>"); //if(hasListener) { pageContext.forceWrite("<script language = \"JavaScript\" type=\"text/javascript\">\n"); if(onsubmit!=null)pageContext.forceWrite("function "+checkName+"() { if("+funcName+".check()){"+onsubmit+"\nreturn true;}else {return false;}}\n"); else pageContext.forceWrite("function "+checkName+"() { return "+funcName+".check();}\n"); if(onreset!=null)pageContext.forceWrite("function "+resetName+"() {"+onreset+"\n}\n"); if(onload!=null)pageContext.forceWrite("function "+loadName+"() {"+onload+"\n}\n"); pageContext.forceWrite("\n</script>"); //} pageContext.forceWrite("<form"); Iterator<Entry<Key, Object>> it = attributes.entryIterator(); Entry<Key, Object> e; while(it.hasNext()) { e = it.next(); pageContext.forceWrite(" "); pageContext.forceWrite(e.getKey().getString()); pageContext.forceWrite("="); pageContext.forceWrite(de(Caster.toString(e.getValue()))); } if(passthrough!=null) { pageContext.forceWrite(" "); pageContext.forceWrite(passthrough); } pageContext.forceWrite(">"); return EVAL_BODY_INCLUDE; } @Override public int doEndTag() throws PageException { String funcName="railo_form_"+count; try { pageContext.forceWrite("</form><!-- name:"+name+" --><script>\n"); pageContext.forceWrite(funcName+"=new RailoForms("+js(name)+","+js(onError)+");\n"); Iterator it = inputs.keySet().iterator(); while(it.hasNext()) { InputBean input=(InputBean) inputs.get(it.next()); pageContext.forceWrite(funcName+".addInput("+js(input.getName())+","+input.isRequired()+ ","+input.getType()+","+input.getValidate()+ ","+(input.getPattern())+","+js(input.getMessage())+ ","+js(input.getOnError())+","+js(input.getOnValidate())+ ","+range(input.getRangeMin())+","+range(input.getRangeMax())+ ","+(input.getMaxLength())+ ");\n"); } pageContext.forceWrite("</script>"); } catch (IOException e) { throw Caster.toPageException(e); } return EVAL_PAGE; } private String range(double range) { if(!Decision.isValid(range)) return "null"; return Caster.toString(range); } private String de(String str) { try { return DE.call(pageContext,str); } catch (ExpressionException e) { return "\"\""; } } private String js(String str) { if(str==null) return "null"; return "'"+JSStringFormat.call(pageContext,str)+"'"; } /** * @param input * @throws ApplicationException */ public void setInput(InputBean input) throws ApplicationException { if(input.getType()==Input.TYPE_TEXT || input.getType()==Input.TYPE_PASSWORD) { InputBean i=(InputBean)inputs.get(input.getName().toLowerCase()); if(i!=null && (i.getType()==Input.TYPE_TEXT || i.getType()==Input.TYPE_PASSWORD)) { throw new ApplicationException("duplicate input field ["+i.getName()+"] for form","a text or password field must be unique"); } } //if(StringUtil.isEmpty(input.getOnError(),true) && !StringUtil.isEmpty(onError,true)) // input.setOnError(onError); inputs.put(input.getName().toLowerCase(),input); } /** * @return Returns the name. */ public String getName() { return name; } /** * @return Returns the onsubmit. */ public String getOnsubmit() { return onsubmit; } public int getFormat() { return format; } public String getArchive() { return archive; } public String getCodebase() { return codebase; } }