diff -r 671fc517fe17 -r df08556c5c7c javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Tue Mar 19 11:51:08 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Thu Apr 11 20:44:46 2013 +0200 @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Method; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javafx.scene.web.WebEngine; @@ -37,7 +38,8 @@ private static final Logger LOG = Logger.getLogger(Knockout.class.getName()); /** used by tests */ static Knockout next; - + private final Object model; + static { BufferedReader r = new BufferedReader(new InputStreamReader(Knockout.class.getResourceAsStream("knockout-2.2.1.js"))); StringBuilder sb = new StringBuilder(); @@ -58,42 +60,34 @@ } - private final Object bindings; - - Knockout(Object bindings) { - this.bindings = bindings; + Knockout(Object model) { + this.model = model == null ? this : model; } public static Knockout applyBindings( - Class modelClass, M model, String[] propsGettersAndSetters + Object model, String[] propsGettersAndSetters, + String[] methodsAndSignatures + ) { + applyImpl(propsGettersAndSetters, model.getClass(), model, model, methodsAndSignatures); + return new Knockout(model); + } + public static Knockout applyBindings( + Class modelClass, M model, String[] propsGettersAndSetters, + String[] methodsAndSignatures ) { Object bindings = next; next = null; if (bindings == null) { bindings = web().executeScript("new Object()"); } - for (int i = 0; i < propsGettersAndSetters.length; i += 4) { - try { - Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]); - bind(bindings, model, propsGettersAndSetters[i], - propsGettersAndSetters[i + 1], - propsGettersAndSetters[i + 2], - getter.getReturnType().isPrimitive() - ); - } catch (NoSuchMethodException ex) { - throw new IllegalStateException(ex.getMessage()); - } - } + applyImpl(propsGettersAndSetters, modelClass, bindings, model, methodsAndSignatures); applyBindings(bindings); return new Knockout(bindings); } - @JavaScriptBody(args = { "prop" }, body = - "this[prop].valueHasMutated();" - ) public void valueHasMutated(String prop) { LOG.log(Level.FINE, "property mutated: {0}", prop); - JSObject koProp = (JSObject) ((JSObject)bindings).getMember(prop); + JSObject koProp = (JSObject) ((JSObject)model).getMember(prop); koProp.call("valueHasMutated"); } @@ -102,23 +96,24 @@ public static void triggerEvent(String id, String ev) { } - @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive" }, body = + @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive", "array" }, body = "var bnd = {\n" - + " read: function() {\n" + + " 'read': function() {\n" + " var v = model[getter]();\n" + + " if (array) v = v.koArray();\n" + " return v;\n" + " },\n" - + " owner: bindings\n" + + " 'owner': bindings\n" + "};\n" + "if (setter != null) {\n" - + " bnd.write = function(val) {\n" + + " bnd['write'] = function(val) {\n" + " model[setter](primitive ? new Number(val) : val);\n" + " };\n" + "}\n" - + "bindings[prop] = ko.computed(bnd);" + + "bindings[prop] = ko['computed'](bnd);" ) private static void bind( - Object bindings, Object model, String prop, String getter, String setter, boolean primitive + Object bindings, Object model, String prop, String getter, String setter, boolean primitive, boolean array ) { WebEngine e = web(); JSObject bnd = (JSObject) e.executeScript("var x = {}; x.bnd = " @@ -153,6 +148,13 @@ int under = mangled.indexOf("__"); return mangled.substring(0, under); } + @JavaScriptBody(args = { "bindings", "model", "prop", "sig" }, body = + "bindings[prop] = function(data, ev) { model[sig](data, ev); };" + ) + private static void expose( + Object bindings, Object model, String prop, String sig + ) { + } @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);") private static void applyBindings(Object bindings) { @@ -164,4 +166,29 @@ return (WebEngine) System.getProperties().get("webEngine"); } + + private static void applyImpl( + String[] propsGettersAndSetters, + Class modelClass, + Object bindings, + Object model, + String[] methodsAndSignatures + ) throws IllegalStateException, SecurityException { + for (int i = 0; i < propsGettersAndSetters.length; i += 4) { + try { + Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]); + bind(bindings, model, propsGettersAndSetters[i], + propsGettersAndSetters[i + 1], + propsGettersAndSetters[i + 2], + getter.getReturnType().isPrimitive(), + List.class.isAssignableFrom(getter.getReturnType())); + } catch (NoSuchMethodException ex) { + throw new IllegalStateException(ex.getMessage()); + } + } + for (int i = 0; i < methodsAndSignatures.length; i += 2) { + expose( + bindings, model, methodsAndSignatures[i], methodsAndSignatures[i + 1]); + } + } }