1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
7 import org.ibex.util.*;
9 import java.lang.reflect.*;
13 import javax.servlet.*;
14 import javax.servlet.http.*;
16 // tabbing order? accessability key?
17 // the 'name' property is taken from the field name, with underscores converted to spaces
18 // the way I'm doing Radio() { ... } right now is how multi-select menus ought to work
19 // autogenerate <LABEL> elements?
20 // <TD><LABEL for="fname">First Name</LABEL>
21 // <TD><INPUT type="text" name="firstname" id="fname">
23 public abstract class Form extends HttpServlet {
26 public Form(String action) { this.action = action; }
28 public static class TestForm extends Form {
29 public TestForm() { super("/foo"); }
30 public boolean[] poo = new boolean[] { true, false, true, true };
31 public String[] poo3 = new String[] { "a", "b", "c" };
32 public boolean poo2 = true;
33 public String myName = "blarg";
34 public Radio day = new Radio() { public boolean sun, mon, tue, wed, thu, fri, sat; };
35 public CheckBox vegetarian = new CheckBox(); // label taken from field name
36 public CheckBox vegan = new CheckBox("are you vegan?");
37 public Text firstName = new Text("First Name");
38 public Text lastName = new Text();
40 public CheckBox[] checkboxes = new CheckBox[] {
45 //public Option[] options = new Option[] { new Option("foo"); }
47 public static void main(String[] s) throws Exception {
48 Form sample = new TestForm();
49 System.out.println(sample.emit());
52 //public void sendRedirect(HttpServletResponse response) throws IOException {
53 //response.sendRedirect(uri);
55 public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { doGet(request, response); }
56 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
57 Field[] fields = this.getClass().getFields();
58 for(int i=0; i<fields.length; i++) {
60 Class c = f.getType();
61 String name = f.getName();
62 Log.warn("param", name + " = " + request.getParameter(name));
66 //public abstract void validate(HttpServletRequest req);
67 //public abstract void go(HttpServletRequest req, HttpServletResponse resp);
70 JSArray ret = new JSArray();
71 Field[] fields = this.getClass().getFields();
72 for(int i=0; i<fields.length; i++) {
74 String name = f.getName();
80 public String emit() throws Exception { return emit(null); }
81 public String emit(String fieldName) throws Exception {
82 Field[] fields = this.getClass().getFields();
83 StringBuffer ret = new StringBuffer();
84 if (fieldName==null) ret.append("<form xmlns='http://www.w3.org/1999/xhtml'"+q("action",action)+">\n");
85 for(int i=0; i<fields.length; i++) {
87 Class c = f.getType();
88 String name = f.getName();
89 if (fieldName != null && !fieldName.equals(name)) continue;
90 if (c == Boolean.TYPE) {
91 boolean b = ((Boolean)f.get(this)).booleanValue();
92 ret.append(" <input type='checkbox'"+q("name",name)+(b?" checked='on'":"")+"/>\n");
93 } else if (c == String.class) {
95 Text t = new Text(f.getName());
96 t.value = ((String)f.get(this));
99 } else if (c.isArray()) {
100 Class c2 = c.getComponentType();
101 int len = Array.getLength(f.get(this));
102 for(int j=0; j<len; j++) {
104 if (c2 == Boolean.TYPE) {
105 boolean b = ((Boolean)Array.get(f.get(this),j)).booleanValue();
106 ret.append(" <input type='checkbox'"+q("name",name+"_"+j)+(b?" checked='on'":"")+"/>\n");
107 } else if (c2 == String.class) {
108 Text t = new Text(f.getName()+"_"+j);
109 t.value = (String)Array.get(f.get(this),j);
110 ret.append(t.emit());
112 Element[] o = (Element[])f.get(this);
113 o[j].name = name+"_"+j;
114 ret.append(o[j].emit());
118 } else if (!Element.class.isAssignableFrom(c)) { // nothing
120 Element e = (Element)f.get(this);
122 e = (Element)c.newInstance();
125 if (e.name==null) e.name = name;
127 ret.append(e.emit());
131 if (fieldName==null) ret.append("</form>\n");
132 return ret.toString();
135 public static String q(String key, String val) { return val==null ? "" : " "+key+"='"+val+"'"; }
136 public static String q(String key, int val) { return key+" ='"+val+"'"; }
137 public static String q(String key, boolean val) { return val ? " "+key+"=true" : ""; }
138 public static String escape(String s) { return s.replaceAll("&","&").replaceAll("<",">").replaceAll("'","'"); }
140 public static abstract class Element {
141 public String name = null;
142 public boolean disabled = false;
143 public String id = null;
144 public int size = -1;
145 public String alt = null;
147 public Element(String name) { this.name = name; }
148 public String fields() { return q("id",id)+q("disabled", disabled)+q("alt", alt); }
149 public String emit() { return "<input"+q("name",name)+q("type",type())+fields()+"/>"; }
150 public String type() {
151 String t = this.getClass().getName().toLowerCase();
152 if (t.indexOf('.') != -1) t = t.substring(t.lastIndexOf('.')+1);
153 if (t.indexOf('$') != -1) t = t.substring(t.lastIndexOf('$')+1);
158 public static class Text extends Element{
159 public String value = null;
160 public boolean ro = false;
161 public char maxLength = 0;
162 public String fields(){return super.fields()+q("value",value)+q("readonly",ro)+(maxLength>0?q("maxlength",maxLength):"");}
163 public Text() { super(); }
164 public Text(String name) { super(name); }
166 public static class Password extends Text { }
167 public static class Hidden extends Text { }
168 public static class TextArea extends Text {
169 int rows; // relation to 'size'?
171 private TextArea() { }
172 public TextArea(int rows, int cols) { this.rows=rows; this.cols=cols; }
173 public String fields() { return super.fields()+q("rows",rows)+q("cols",cols); }
174 public String emit() { return "<textarea"+fields()+">\n"+escape(value)+"</textarea>"; }
177 public static class Radio extends Element {
178 public String emit() {
179 StringBuffer ret = new StringBuffer();
181 Class c = this.getClass();
182 Field[] f = c.getFields();
183 for(int i=0; i<f.length; i++) {
184 if (f[i].getType() != Boolean.TYPE) continue;
185 if (f[i].getDeclaringClass().isAssignableFrom(Radio.class)) continue;
186 boolean b = ((Boolean)f[i].get(this)).booleanValue();
188 ret.append("<input type='radio'"+q("name",name)+q("value",f[i].getName())+(b?" checked='true'":"")+"/>");
191 } catch (Exception e) { e.printStackTrace(); }
192 return ret.toString();
196 public static class Submit extends Element { public Submit(String label) { super(label); } }
197 public static class Reset extends Element { public Reset(String label) { super(label); } }
198 public static class Upload extends Element {
200 public Upload(String label) { super(label); }
201 public Upload(String label, String filename) { super(label); this.filename=filename; }
204 public static class CheckBox extends Element {
206 public String fields() { return super.fields()+q("on",on); }
207 public CheckBox() { super(); }
208 public CheckBox(String label) { super(label); }
212 public static class Image extends Element {
215 public Image(String url, String alt) { }
224 // size == number of visible rows
225 public static class Menu extends Element {
226 // force a pre-selected option
227 public static class Item {
230 boolean selected = false;
232 public static class Group extends Item { }
233 public Menu(Item[] items) { }
234 public boolean multipleSelect;