javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java
branchfx
changeset 969 df08556c5c7c
parent 852 671fc517fe17
parent 909 e51a474fcf79
child 970 8fefdd067b9e
     1.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java	Tue Mar 19 11:51:08 2013 +0100
     1.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java	Thu Apr 11 20:44:46 2013 +0200
     1.3 @@ -21,6 +21,7 @@
     1.4  import java.io.IOException;
     1.5  import java.io.InputStreamReader;
     1.6  import java.lang.reflect.Method;
     1.7 +import java.util.List;
     1.8  import java.util.logging.Level;
     1.9  import java.util.logging.Logger;
    1.10  import javafx.scene.web.WebEngine;
    1.11 @@ -37,7 +38,8 @@
    1.12      private static final Logger LOG = Logger.getLogger(Knockout.class.getName());
    1.13      /** used by tests */
    1.14      static Knockout next;
    1.15 -    
    1.16 +    private final Object model;
    1.17 +
    1.18      static {
    1.19          BufferedReader r = new BufferedReader(new InputStreamReader(Knockout.class.getResourceAsStream("knockout-2.2.1.js")));
    1.20          StringBuilder sb = new StringBuilder();
    1.21 @@ -58,42 +60,34 @@
    1.22      }
    1.23      
    1.24      
    1.25 -    private final Object bindings;
    1.26 -    
    1.27 -    Knockout(Object bindings) {
    1.28 -        this.bindings = bindings;
    1.29 +    Knockout(Object model) {
    1.30 +        this.model = model == null ? this : model;
    1.31      }
    1.32      
    1.33      public static <M> Knockout applyBindings(
    1.34 -        Class<M> modelClass, M model, String[] propsGettersAndSetters
    1.35 +        Object model, String[] propsGettersAndSetters,
    1.36 +        String[] methodsAndSignatures
    1.37 +    ) {
    1.38 +        applyImpl(propsGettersAndSetters, model.getClass(), model, model, methodsAndSignatures);
    1.39 +        return new Knockout(model);
    1.40 +    }
    1.41 +    public static <M> Knockout applyBindings(
    1.42 +        Class<M> modelClass, M model, String[] propsGettersAndSetters,
    1.43 +        String[] methodsAndSignatures
    1.44      ) {
    1.45          Object bindings = next;
    1.46          next = null;
    1.47          if (bindings == null) {
    1.48              bindings = web().executeScript("new Object()");
    1.49          }
    1.50 -        for (int i = 0; i < propsGettersAndSetters.length; i += 4) {
    1.51 -            try {
    1.52 -                Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]);
    1.53 -                bind(bindings, model, propsGettersAndSetters[i],
    1.54 -                    propsGettersAndSetters[i + 1],
    1.55 -                    propsGettersAndSetters[i + 2],
    1.56 -                    getter.getReturnType().isPrimitive()
    1.57 -                );
    1.58 -            } catch (NoSuchMethodException ex) {
    1.59 -                throw new IllegalStateException(ex.getMessage());
    1.60 -            }
    1.61 -        }
    1.62 +        applyImpl(propsGettersAndSetters, modelClass, bindings, model, methodsAndSignatures);
    1.63          applyBindings(bindings);
    1.64          return new Knockout(bindings);
    1.65      }
    1.66  
    1.67 -    @JavaScriptBody(args = { "prop" }, body =
    1.68 -        "this[prop].valueHasMutated();"
    1.69 -    )
    1.70      public void valueHasMutated(String prop) {
    1.71          LOG.log(Level.FINE, "property mutated: {0}", prop);
    1.72 -        JSObject koProp = (JSObject) ((JSObject)bindings).getMember(prop);
    1.73 +        JSObject koProp = (JSObject) ((JSObject)model).getMember(prop);
    1.74          koProp.call("valueHasMutated");
    1.75      }
    1.76      
    1.77 @@ -102,23 +96,24 @@
    1.78      public static void triggerEvent(String id, String ev) {
    1.79      }
    1.80      
    1.81 -    @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive" }, body =
    1.82 +    @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive", "array" }, body =
    1.83            "var bnd = {\n"
    1.84 -        + "  read: function() {\n"
    1.85 +        + "  'read': function() {\n"
    1.86          + "    var v = model[getter]();\n"
    1.87 +        + "    if (array) v = v.koArray();\n"
    1.88          + "    return v;\n"
    1.89          + "  },\n"
    1.90 -        + "  owner: bindings\n"
    1.91 +        + "  'owner': bindings\n"
    1.92          + "};\n"
    1.93          + "if (setter != null) {\n"
    1.94 -        + "  bnd.write = function(val) {\n"
    1.95 +        + "  bnd['write'] = function(val) {\n"
    1.96          + "    model[setter](primitive ? new Number(val) : val);\n"
    1.97          + "  };\n"
    1.98          + "}\n"
    1.99 -        + "bindings[prop] = ko.computed(bnd);"
   1.100 +        + "bindings[prop] = ko['computed'](bnd);"
   1.101      )
   1.102      private static void bind(
   1.103 -        Object bindings, Object model, String prop, String getter, String setter, boolean primitive
   1.104 +        Object bindings, Object model, String prop, String getter, String setter, boolean primitive, boolean array
   1.105      ) {
   1.106          WebEngine e = web();
   1.107          JSObject bnd = (JSObject) e.executeScript("var x = {}; x.bnd = "
   1.108 @@ -153,6 +148,13 @@
   1.109          int under = mangled.indexOf("__");
   1.110          return mangled.substring(0, under);
   1.111      }
   1.112 +    @JavaScriptBody(args = { "bindings", "model", "prop", "sig" }, body = 
   1.113 +        "bindings[prop] = function(data, ev) { model[sig](data, ev); };"
   1.114 +    )
   1.115 +    private static void expose(
   1.116 +        Object bindings, Object model, String prop, String sig
   1.117 +    ) {
   1.118 +    }
   1.119      
   1.120      @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);")
   1.121      private static void applyBindings(Object bindings) {
   1.122 @@ -164,4 +166,29 @@
   1.123          return (WebEngine) System.getProperties().get("webEngine");
   1.124      }
   1.125      
   1.126 +    
   1.127 +    private static void applyImpl(
   1.128 +        String[] propsGettersAndSetters,
   1.129 +        Class<?> modelClass,
   1.130 +        Object bindings,
   1.131 +        Object model,
   1.132 +        String[] methodsAndSignatures
   1.133 +    ) throws IllegalStateException, SecurityException {
   1.134 +        for (int i = 0; i < propsGettersAndSetters.length; i += 4) {
   1.135 +            try {
   1.136 +                Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]);
   1.137 +                bind(bindings, model, propsGettersAndSetters[i],
   1.138 +                    propsGettersAndSetters[i + 1],
   1.139 +                    propsGettersAndSetters[i + 2],
   1.140 +                    getter.getReturnType().isPrimitive(),
   1.141 +                    List.class.isAssignableFrom(getter.getReturnType()));
   1.142 +            } catch (NoSuchMethodException ex) {
   1.143 +                throw new IllegalStateException(ex.getMessage());
   1.144 +            }
   1.145 +        }
   1.146 +        for (int i = 0; i < methodsAndSignatures.length; i += 2) {
   1.147 +            expose(
   1.148 +                bindings, model, methodsAndSignatures[i], methodsAndSignatures[i + 1]);
   1.149 +        }
   1.150 +    }
   1.151  }