added Form, other minor changes
[org.ibex.xt.git] / src / org / ibex / xt / Template.java
index b585033..f8c4e8d 100644 (file)
@@ -41,30 +41,32 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
     }
 
     public static Node transform(Node n, Scope scope) {
-        if (n.cdata != null) n.cdata = eval(n.cdata, scope).toString();
-        else for(int i=1; i<n.numattrs*2; i+=2) n.attrs[i] = eval(n.attrs[i], scope).toString();
-        return n;
+        try {
+            if (n.cdata != null) n.cdata = eval(n.cdata, scope).toString();
+            else for(int i=1; i<n.numattrs*2; i+=2) n.attrs[i] = eval(n.attrs[i], scope).toString();
+            return n;
+        } catch (JSExn e) { throw new RuntimeException(e); }
     }
 
-    private static Object eval(String s, Scope scope) {
+    private static Object eval(String s, Scope scope) throws JSExn {
         if (s == null) return null;
         StringBuffer ret = new StringBuffer();
         for(boolean first = true; s.indexOf("${") != -1; first = false) {
             ret.append(s.substring(0, s.indexOf("${")));
             String s2 = s.substring(s.indexOf("${")+2);
-            Object app = exec("return (" + s2.substring(0, s2.indexOf('}')) + ");\n", scope);
+            JS app = exec("return (" + s2.substring(0, s2.indexOf('}')) + ");\n", scope);
             s = s.substring(s.indexOf('}') + 1);
             //if (first && s.trim().length() == 0) return app;
-            if (!(app == null || app instanceof String || app instanceof Number || app instanceof Boolean))
+            if (!(app == null || app instanceof JSPrimitive))
                 throw new RuntimeException("javascripts within ${...} can only return strings, numbers, and booleans; not a " +
                                            app.getClass().getName());
-            ret.append(app == null ? "null" : app.toString());
+            ret.append(app == null ? "null" : JSU.toString(app));
         }
         ret.append(s);
         return ret.toString();
     }
 
-    public static Object exec(String s, Scope scope) {
+    public static JS exec(String s, Scope scope) {
         try {
             return JSU.cloneWithNewGlobalScope(JSU.fromReader("input", 0, new StringReader(s)), scope).call(null,null);
         } catch (Exception e) {
@@ -86,7 +88,8 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
     public boolean __read(final Node n) {
         if (!upstreamRead(n)) return false;
         if (n.cdata != null) return true;
-        final String uri = n.uri;
+        String uri = n.uri;
+        if (uri == null) uri = "http://www.w3.org/1999/xhtml";  // FIXME FIXME FIXME!!!!
         final String name = n.name;
         if (uri.indexOf(':') == -1)
             throw new RuntimeException("uri does not contain a colon: " + uri + " (tag name " + name + ")");
@@ -96,11 +99,15 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
         } else if (method.equals("webinf")) {
             return graft(newTemplate(servletscope, copyNodeToScope(transform(n, scope), new Scope(servletscope)),
                                      servletscope.getRealPath("/") + "/WEB-INF/" + rest + name), n).upstreamRead(n);
+        } else if (uri.equals("http://xt.ibex.org/form")) {
+            return graft(new InputTag(n.name), n).upstreamRead(n);
         } else if (uri.equals("http://xt.ibex.org/")) {
             //#switch(name)
+            case "form":  return graft(new FormTag(n.attr("class")), n).upstreamRead(n);
+            case "input": return graft(new InputTag(n.attr("field")), n).upstreamRead(n);
             case "if":       
                 transform(n, scope);
-                return graft((Node.Stream.Functor)("true".equals(n.attr("if")) ? new DropTag() : new DropAll()), n).upstreamRead(n);
+                return graft((Node.Stream.Functor)("true".equals(n.attr("if"))?new DropTag():new DropAll()), n).upstreamRead(n);
             case "js":       return graft(new JsTag(scope), n).upstreamRead(n);
             case "foreach":  return graft(new ForEach(n, scope), n).upstreamRead(n);
             case "children":
@@ -127,6 +134,7 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
                 JSArray a = ((JSArray)exec("return (" + n.attr("in").toString() + ");", this.scope = s));
                 while(true) {
                     JS o = a.call(JSU.S("pop"), new JS[] { });
+                   System.out.println("called pop on a "+a.getClass().getName()+" of length " +a.size()+" , got " + (o==null ? null : o.getClass().getName()));
                     if (o == null) break;
                     array.push(o);
                 }
@@ -156,24 +164,42 @@ public class Template extends Node.Stream.Filter implements Node.Stream.Functor
         }
     }
 
-    public static class Scope extends JS.Immutable {
-        private final JS parent;
-        private final Hash declared = new Hash();
-        public Scope(JS parent) { this.parent = parent; }
-        public JS get(JS key) throws JSExn {
-            if (declared.get(key)!=null) return super.get(key);
-            return parent.get(key);
-        }
-        public void put(JS key, JS val) throws JSExn {
-            if (declared.get(key)!=null) super.put(key, val);
-            else parent.put(key, val);
+    private class InputTag implements Node.Stream.Functor {
+        final String fieldName;
+        public InputTag(String fieldName) { this.fieldName = fieldName; }
+        public Node.Stream wrap(Node.Stream kids) {
+            try {
+                return new Node.Stream.FromXML(new StringReader(servletscope.currentForm.emit(fieldName)));
+            } catch (Exception e) { Log.warn(this, e); return null; }
         }
-        public void declare(JS key) { declared.put(key, Boolean.TRUE); }
-        public void declare(String key) { declare(JSU.S(key)); }
-        public void undeclare(JS key) { declared.remove(key); }
-        public void undeclare(String key) { undeclare(JSU.S(key)); }
     }
 
+    private class FormTag implements Node.Stream.Functor {
+        final String classname;
+        public FormTag(String classname) { this.classname = classname; }
+        public Node.Stream wrap(final Node.Stream kids) {
+            try {
+                servletscope.currentForm = (Form)Class.forName(classname).newInstance();
+                Log.warn("emit", servletscope.currentForm.emit());
+                return new Node.Stream() {
+                        boolean done = false;
+                        public boolean _read(Node n) {
+                            if (done) return kids._read(n);
+                            done = true;
+                            n.clear();
+                            n.name = "form";
+                            n.uri = "http://www.w3.org/1999/xhtml";
+                            n.numattrs = 1;
+                            n.attrs = new String[] { "action", "/servlet/"+classname };
+                            return true;
+                        }
+                    };
+            } catch (Exception e) {
+                Log.warn(this, e);
+                return null;
+            }
+        } }
     private class DropTag implements Node.Stream.Functor {
         public Node.Stream wrap(Node.Stream kids) {
             return kids;