+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
+package org.ibex.xt;
+import org.ibex.js.*;
+import org.ibex.util.*;
+import org.ibex.io.*;
+import java.lang.reflect.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+// tabbing order? accessability key?
+// the 'name' property is taken from the field name, with underscores converted to spaces
+// the way I'm doing Radio() { ... } right now is how multi-select menus ought to work
+// autogenerate <LABEL> elements?
+// <TD><LABEL for="fname">First Name</LABEL>
+// <TD><INPUT type="text" name="firstname" id="fname">
+
+public abstract class Form extends HttpServlet {
+
+ final String action;
+ public Form(String action) { this.action = action; }
+
+ public static class TestForm extends Form {
+ public TestForm() { super("/foo"); }
+ public boolean[] poo = new boolean[] { true, false, true, true };
+ public String[] poo3 = new String[] { "a", "b", "c" };
+ public boolean poo2 = true;
+ public String myName = "blarg";
+ public Radio day = new Radio() { public boolean sun, mon, tue, wed, thu, fri, sat; };
+ public CheckBox vegetarian = new CheckBox(); // label taken from field name
+ public CheckBox vegan = new CheckBox("are you vegan?");
+ public Text firstName = new Text("First Name");
+ public Text lastName = new Text();
+ public Password pass;
+ public CheckBox[] checkboxes = new CheckBox[] {
+ new CheckBox("foo"),
+ new CheckBox("bar"),
+ new CheckBox("baz")
+ };
+ //public Option[] options = new Option[] { new Option("foo"); }
+ }
+ public static void main(String[] s) throws Exception {
+ Form sample = new TestForm();
+ System.out.println(sample.emit());
+ }
+
+ public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { doGet(request, response); }
+ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ Field[] fields = this.getClass().getFields();
+ for(int i=0; i<fields.length; i++) {
+ Field f = fields[i];
+ Class c = f.getType();
+ String name = f.getName();
+ Log.warn("param", name + " = " + request.getParameter(name));
+ }
+ }
+
+ //public abstract void validate(HttpServletRequest req);
+ //public abstract void go(HttpServletRequest req, HttpServletResponse resp);
+
+ public JS fields() {
+ JSArray ret = new JSArray();
+ Field[] fields = this.getClass().getFields();
+ for(int i=0; i<fields.length; i++) {
+ Field f = fields[i];
+ String name = f.getName();
+ ret.add(JSU.S(name));
+ }
+ return ret;
+ }
+
+ public String emit() throws Exception { return emit(null); }
+ public String emit(String fieldName) throws Exception {
+ Field[] fields = this.getClass().getFields();
+ StringBuffer ret = new StringBuffer();
+ if (fieldName==null) ret.append("<form xmlns='http://www.w3.org/1999/xhtml'"+q("action",action)+">\n");
+ for(int i=0; i<fields.length; i++) {
+ Field f = fields[i];
+ Class c = f.getType();
+ String name = f.getName();
+ if (fieldName != null && !fieldName.equals(name)) continue;
+ if (c == Boolean.TYPE) {
+ boolean b = ((Boolean)f.get(this)).booleanValue();
+ ret.append(" <input type='checkbox'"+q("name",name)+(b?" checked='on'":"")+"/>\n");
+ } else if (c == String.class) {
+ ret.append(" ");
+ Text t = new Text(f.getName());
+ t.value = ((String)f.get(this));
+ ret.append(t.emit());
+ ret.append('\n');
+ } else if (c.isArray()) {
+ Class c2 = c.getComponentType();
+ int len = Array.getLength(f.get(this));
+ for(int j=0; j<len; j++) {
+ ret.append(" ");
+ if (c2 == Boolean.TYPE) {
+ boolean b = ((Boolean)Array.get(f.get(this),j)).booleanValue();
+ ret.append(" <input type='checkbox'"+q("name",name+"_"+j)+(b?" checked='on'":"")+"/>\n");
+ } else if (c2 == String.class) {
+ Text t = new Text(f.getName()+"_"+j);
+ t.value = (String)Array.get(f.get(this),j);
+ ret.append(t.emit());
+ } else {
+ Element[] o = (Element[])f.get(this);
+ o[j].name = name+"_"+j;
+ ret.append(o[j].emit());
+ }
+ ret.append('\n');
+ }
+ } else if (!Element.class.isAssignableFrom(c)) { // nothing
+ } else {
+ Element e = (Element)f.get(this);
+ if (e==null) {
+ e = (Element)c.newInstance();
+ f.set(this, e);
+ }
+ if (e.name==null) e.name = name;
+ ret.append(" ");
+ ret.append(e.emit());
+ ret.append('\n');
+ }
+ }
+ if (fieldName==null) ret.append("</form>\n");
+ return ret.toString();
+ }
+
+ public static String q(String key, String val) { return val==null ? "" : " "+key+"='"+val+"'"; }
+ public static String q(String key, int val) { return key+" ='"+val+"'"; }
+ public static String q(String key, boolean val) { return val ? " "+key+"=true" : ""; }
+ public static String escape(String s) { return s.replaceAll("&","&").replaceAll("<",">").replaceAll("'","'"); }
+
+ public static abstract class Element {
+ public String name = null;
+ public boolean disabled = false;
+ public String id = null;
+ public int size = -1;
+ public String alt = null;
+ public Element() { }
+ public Element(String name) { this.name = name; }
+ public String fields() { return q("id",id)+q("disabled", disabled)+q("alt", alt); }
+ public String emit() { return "<input"+q("name",name)+q("type",type())+fields()+"/>"; }
+ public String type() {
+ String t = this.getClass().getName().toLowerCase();
+ if (t.indexOf('.') != -1) t = t.substring(t.lastIndexOf('.')+1);
+ if (t.indexOf('$') != -1) t = t.substring(t.lastIndexOf('$')+1);
+ return t;
+ }
+ }
+
+ public static class Text extends Element{
+ public String value = null;
+ public boolean ro = false;
+ public char maxLength = 0;
+ public String fields(){return super.fields()+q("value",value)+q("readonly",ro)+(maxLength>0?q("maxlength",maxLength):"");}
+ public Text() { super(); }
+ public Text(String name) { super(name); }
+ }
+ public static class Password extends Text { }
+ public static class Hidden extends Text { }
+ public static class TextArea extends Text {
+ int rows; // relation to 'size'?
+ int cols;
+ private TextArea() { }
+ public TextArea(int rows, int cols) { this.rows=rows; this.cols=cols; }
+ public String fields() { return super.fields()+q("rows",rows)+q("cols",cols); }
+ public String emit() { return "<textarea"+fields()+">\n"+escape(value)+"</textarea>"; }
+ }
+
+ public static class Radio extends Element {
+ public String emit() {
+ StringBuffer ret = new StringBuffer();
+ try {
+ Class c = this.getClass();
+ Field[] f = c.getFields();
+ for(int i=0; i<f.length; i++) {
+ if (f[i].getType() != Boolean.TYPE) continue;
+ if (f[i].getDeclaringClass().isAssignableFrom(Radio.class)) continue;
+ boolean b = ((Boolean)f[i].get(this)).booleanValue();
+ ret.append(" ");
+ ret.append("<input type='radio'"+q("name",name)+q("value",f[i].getName())+(b?" checked='true'":"")+"/>");
+ ret.append('\n');
+ }
+ } catch (Exception e) { e.printStackTrace(); }
+ return ret.toString();
+ }
+ }
+
+ public static class Submit extends Element { public Submit(String label) { super(label); } }
+ public static class Reset extends Element { public Reset(String label) { super(label); } }
+ public static class Upload extends Element {
+ String filename;
+ public Upload(String label) { super(label); }
+ public Upload(String label, String filename) { super(label); this.filename=filename; }
+ }
+
+ public static class CheckBox extends Element {
+ boolean on = false;
+ public String fields() { return super.fields()+q("on",on); }
+ public CheckBox() { super(); }
+ public CheckBox(String label) { super(label); }
+ }
+
+ /*
+ public static class Image extends Element {
+ // usemap, ismap
+ private Image() { }
+ public Image(String url, String alt) { }
+ public String url;
+ public int x;
+ public int y;
+ }
+
+
+ // Option[] -> Menu
+
+ // size == number of visible rows
+ public static class Menu extends Element {
+ // force a pre-selected option
+ public static class Item {
+ String label;
+ String value;
+ boolean selected = false;
+ }
+ public static class Group extends Item { }
+ public Menu(Item[] items) { }
+ public boolean multipleSelect;
+ }
+ */
+}