eval expressions in normal html attributes
authorcrawshaw <crawshaw@ibex.org>
Thu, 25 Nov 2004 15:43:31 +0000 (15:43 +0000)
committercrawshaw <crawshaw@ibex.org>
Thu, 25 Nov 2004 15:43:31 +0000 (15:43 +0000)
darcs-hash:20041125154331-2eb37-976fcba80f60a56b479f872d116dc0c6ba438a6d.gz

src/java/org/ibex/xt/JSLeaf.java
src/java/org/ibex/xt/Template.java

index 2def4c1..63bffbd 100644 (file)
@@ -1,5 +1,6 @@
 package org.ibex.xt;
 
+import java.io.Reader;
 import java.io.Serializable;
 import java.io.StringReader;
 import java.io.Writer;
@@ -34,42 +35,53 @@ public class JSLeaf implements Tree.Leaf, Serializable {
             while (e != null && !(e instanceof JSLeaf)) e = e.getParent();
             scope = new JSScope(e == null ? null : ((JSLeaf)e).scope());
         }
-
         return scope;
     }
 
-    public void out(OutputStream o) throws IOException { wrapped.out(o); }
     public void out(Writer w) throws IOException { wrapped.out(w); }
+    public void out(OutputStream o) throws IOException { wrapped.out(o); }
 
     protected Object eval(String s) {
         if (s == null) return null;
+
         StringBuffer ret = new StringBuffer();
-        while (s.indexOf("${") != -1) {
-            ret.append(s.substring(0, s.indexOf("${")));
-            String s2 = s.substring(s.indexOf("${")+2);
-            Object app = exec("return (" + s2.substring(0, s2.indexOf('}')) + ");\n");
-            s = s.substring(s.indexOf('}') + 1);
-
-            if (!(app == null ||
-                  app instanceof String ||
-                  app instanceof Number ||
-                  app instanceof Boolean))
+        int exp, pos = 0;
+        while ((exp = s.indexOf("${", pos)) >= 0) {
+            ret.append(s.substring(pos, exp));
+            pos = s.indexOf("}", exp);
+            Object app = exec("return (" + s.substring(exp + 2, pos) + ");");
+            pos++;
+
+            if (!(app == null || app instanceof String ||
+                                 app instanceof Number ||
+                                 app instanceof Boolean))
                 throw new Exn("javascripts within ${...} can only return " +
                               "strings, numbers, and booleans; not a " +
                               app.getClass().getName());
-
             ret.append(app == null ? "null" : app.toString());
         }
-        ret.append(s);
+
+        if (pos < s.length()) ret.append(s.substring(pos));
         return ret.toString();
     }
 
     protected Object exec(String s) {
+        StringBuffer ret = new StringBuffer();
+        int exp, pos = 0;
+        while ((exp = s.indexOf("${", pos)) >= 0) {
+            ret.append(s.substring(pos, exp));
+            pos = s.indexOf("}", exp);
+            ret.append("return (");
+            ret.append(s.substring(exp + 2, pos));
+            ret.append(");");
+            pos++;
+        }
+
+        Reader r = new StringReader(ret.toString());
         try {
             return JS.eval(JS.cloneWithNewParentScope(
-                           JS.fromReader("input", 0, new StringReader(s)), scope()));
+                           JS.fromReader("input", 0, r), scope()));
         } catch (IOException e) {
-            e.printStackTrace();
             throw new Exn("error parsing script", e);
         } catch (JSExn e) {
             throw new Exn(e);
@@ -97,29 +109,15 @@ public class JSLeaf implements Tree.Leaf, Serializable {
         public Tree.Attributes getAttributes() { return ((Tree.Element)wrapped).getAttributes(); }
         public Tree.Prefixes getPrefixes()     { return ((Tree.Element)wrapped).getPrefixes(); }
 
+        public void setAttributes(Tree.Attributes a) { ((Tree.Element)wrapped).setAttributes(a); }
+        public void setPrefixes(Tree.Prefixes p) { ((Tree.Element)wrapped).setPrefixes(p); }
+
         public String getQName()     { return ((Tree.Element)wrapped).getQName(); }
         public String getLocalName() { return ((Tree.Element)wrapped).getLocalName(); }
         public String getPrefix()    { return ((Tree.Element)wrapped).getPrefix(); }
         public String getUri()       { return ((Tree.Element)wrapped).getUri(); }
     }
 
-    /** A JSLeaf.Element with the element attributes merged with a second
-     *  element.
-     *
-     *  All functions of the Tree.Element interface are mapped onto the
-     *  primary element, except <tt>getAttributes()</tt>. This function
-     *  returns a MergedAttr instance with the <b>secondary</b> element
-     *  acting as the primary attribute source.
-     */
-    public static class Merge extends Element {
-        private final Tree.Attributes a;
-        public Merge(Tree.Element wrapped, Tree.Element merge) {
-            super(wrapped);
-            a = new MergeAttr(merge.getAttributes(), wrapped.getAttributes());
-        }
-        public Tree.Attributes getAttributes() { return a; }
-    }
-
     /** Creates a single view onto two sets of Attributes, first
      *  checking the <tt>primary</tt> array for an entry, or
      *  otherwise returning any matching entry in the
@@ -151,9 +149,9 @@ public class JSLeaf implements Tree.Leaf, Serializable {
         public String getUri(int i) {
             return i >= a.attrSize() ? b.getUri(i-a.attrSize()) : a.getUri(i); }
         public String getPrefix(int i) {
-            return i >= a.attrSize() ? b.getUri(i-a.attrSize()) : a.getUri(i); }
+            return i >= a.attrSize() ? b.getPrefix(i-a.attrSize()) : a.getPrefix(i); }
         public String getQName(int i) {
-            return i >= a.attrSize() ? b.getUri(i-a.attrSize()) : a.getUri(i); }
+            return i >= a.attrSize() ? b.getQName(i-a.attrSize()) : a.getQName(i); }
         public int attrSize() { return a.attrSize() + b.attrSize(); }
     }
 
index c30ece6..01b8d7e 100644 (file)
@@ -40,10 +40,7 @@ public class Template extends JSLeaf.Element {
             //#end
 
         } else if (uri.startsWith("http://xt.ibex.org/")) {
-            //#switch(uri.substring(19))
-            case "io": System.out.println("ibex.xt.io not yet implemented"); // TODO
-            //#end
-            //throw new JSLeaf.Exn("Unknown XT library: "+uri);
+            throw new JSLeaf.Exn("Unknown XT library: "+uri);
 
         } else if (uri.startsWith("local:")) {
             // merge a new template into this tree
@@ -62,15 +59,16 @@ public class Template extends JSLeaf.Element {
                 e.getChildren().clear();
             }
 
-            Tree.Element merged = new JSLeaf.Merge(t, e);
+            // merge the attributes of the template and its representative
+            t.setAttributes(new JSLeaf.MergeAttr(e.getAttributes(), t.getAttributes()));
 
             // remap the parent of the original element
             if (e.getParent() != null) {
                 List ch = e.getParent().getChildren();
-                ch.set(ch.indexOf(e), merged);
+                ch.set(ch.indexOf(e), t);
             }
 
-            return wrap(merged, s);
+            return wrap(t, s);
         }
 
         e = new Template.AttributeEval(e);
@@ -107,11 +105,14 @@ public class Template extends JSLeaf.Element {
     /** Processes ${...} blocks in attributes, loads applicable
      *  attributes into the JS scope and processes global attributes. */
     public static class AttributeEval extends JSLeaf.Element implements Tree.Attributes {
+        // TODO: hide global attributes from out() function. waiting on util.XMLHelper
         protected Tree.Attributes a;
 
-        public AttributeEval(Tree.Element wrapped) { super(wrapped); a = wrapped.getAttributes(); }
-
-        public Tree.Attributes getAttributes() { return this; }
+        public AttributeEval(Tree.Element wrapped) {
+            super(wrapped);
+            a = wrapped.getAttributes();
+            wrapped.setAttributes(this);
+        }
 
         public int getIndex(String q) { return a.getIndex(q); }
         public int getIndex(String u, String k) { return a.getIndex(u, k); }
@@ -134,7 +135,7 @@ public class Template extends JSLeaf.Element {
                     case "declare":
                         Object d = eval(a.getVal(i));
                         if (!(d instanceof String)) throw new JSLeaf.Exn(
-                            "attribute "+getPrefix()+":declare can only contain a "+
+                            "attribute '"+getPrefix()+":declare' can only contain a "+
                             "space seperated list of variable names to declare.");
                         StringTokenizer st = new StringTokenizer((String)d, " ");
                         while (st.hasMoreTokens()) scope().declare(st.nextToken());