1.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Thu Mar 14 09:22:28 2013 +0100
1.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Mon Mar 18 17:17:00 2013 +0100
1.3 @@ -17,7 +17,14 @@
1.4 */
1.5 package org.apidesign.bck2brwsr.htmlpage;
1.6
1.7 +import java.io.BufferedReader;
1.8 +import java.io.IOException;
1.9 +import java.io.InputStreamReader;
1.10 import java.lang.reflect.Method;
1.11 +import java.util.logging.Level;
1.12 +import java.util.logging.Logger;
1.13 +import javafx.scene.web.WebEngine;
1.14 +import netscape.javascript.JSObject;
1.15 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
1.16 import org.apidesign.bck2brwsr.core.JavaScriptBody;
1.17
1.18 @@ -27,19 +34,43 @@
1.19 */
1.20 @ExtraJavaScript(resource = "/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js")
1.21 public class Knockout {
1.22 + private static final Logger LOG = Logger.getLogger(Knockout.class.getName());
1.23 /** used by tests */
1.24 static Knockout next;
1.25
1.26 - Knockout() {
1.27 + static {
1.28 + BufferedReader r = new BufferedReader(new InputStreamReader(Knockout.class.getResourceAsStream("knockout-2.2.1.js")));
1.29 + StringBuilder sb = new StringBuilder();
1.30 + for (;;) {
1.31 + try {
1.32 + String l = r.readLine();
1.33 + if (l == null) {
1.34 + break;
1.35 + }
1.36 + sb.append(l).append('\n');
1.37 + } catch (IOException ex) {
1.38 + throw new IllegalStateException(ex);
1.39 + }
1.40 + }
1.41 + web().executeScript(sb.toString());
1.42 + Object ko = web().executeScript("ko");
1.43 + assert ko != null : "Knockout library successfully defined 'ko'";
1.44 + }
1.45 +
1.46 +
1.47 + private final Object bindings;
1.48 +
1.49 + Knockout(Object bindings) {
1.50 + this.bindings = bindings;
1.51 }
1.52
1.53 public static <M> Knockout applyBindings(
1.54 Class<M> modelClass, M model, String[] propsGettersAndSetters
1.55 ) {
1.56 - Knockout bindings = next;
1.57 + Object bindings = next;
1.58 next = null;
1.59 if (bindings == null) {
1.60 - bindings = new Knockout();
1.61 + bindings = web().executeScript("new Object()");
1.62 }
1.63 for (int i = 0; i < propsGettersAndSetters.length; i += 4) {
1.64 try {
1.65 @@ -54,13 +85,16 @@
1.66 }
1.67 }
1.68 applyBindings(bindings);
1.69 - return bindings;
1.70 + return new Knockout(bindings);
1.71 }
1.72
1.73 @JavaScriptBody(args = { "prop" }, body =
1.74 "this[prop].valueHasMutated();"
1.75 )
1.76 public void valueHasMutated(String prop) {
1.77 + LOG.log(Level.INFO, "property mutated: {0}", prop);
1.78 + JSObject koProp = (JSObject) ((JSObject)bindings).getMember(prop);
1.79 + koProp.call("valueHasMutated");
1.80 }
1.81
1.82
1.83 @@ -86,8 +120,48 @@
1.84 private static void bind(
1.85 Object bindings, Object model, String prop, String getter, String setter, boolean primitive
1.86 ) {
1.87 + WebEngine e = web();
1.88 + JSObject bnd = (JSObject) e.executeScript("var x = {}; x.bnd = "
1.89 + + "new Function('ko', 'bindings', 'model', 'prop', 'getter', 'setter', 'primitive', '"
1.90 + + "var bnd = {"
1.91 + + " read: function() {"
1.92 + + " try {"
1.93 + + " return model[getter]();"
1.94 + + " } catch (e) {"
1.95 + + " alert(\"Cannot call \" + getter + \" on \" + model + \" error: \" + e);"
1.96 + + " }"
1.97 + + " },"
1.98 + + " owner: bindings"
1.99 + + "};"
1.100 + + "if (setter != null) {"
1.101 + + " bnd.write = function(val) {"
1.102 + + " model[setter](primitive ? new Number(val) : val);"
1.103 + + " };"
1.104 + + "};"
1.105 + + "bindings[prop] = ko.computed(bnd);'"
1.106 + + "); x;");
1.107 +
1.108 + Object ko = e.executeScript("ko");
1.109 + bnd.call("bnd", ko, bindings, model, prop, strip(getter), strip(setter), primitive);
1.110 + LOG.log(Level.INFO, "binding defined for {0}: {1}", new Object[]{prop, ((JSObject)bindings).getMember(prop)});
1.111 + }
1.112 +
1.113 + private static String strip(String mangled) {
1.114 + if (mangled == null) {
1.115 + return null;
1.116 + }
1.117 + int under = mangled.indexOf("__");
1.118 + return mangled.substring(0, under);
1.119 }
1.120
1.121 @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);")
1.122 - private static void applyBindings(Object bindings) {}
1.123 + private static void applyBindings(Object bindings) {
1.124 + JSObject ko = (JSObject) web().executeScript("ko");
1.125 + ko.call("applyBindings", bindings);
1.126 + }
1.127 +
1.128 + private static WebEngine web() {
1.129 + return (WebEngine) System.getProperties().get("webEngine");
1.130 + }
1.131 +
1.132 }
2.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Thu Mar 14 09:22:28 2013 +0100
2.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Mon Mar 18 17:17:00 2013 +0100
2.3 @@ -98,7 +98,7 @@
2.4 try {
2.5 w.append("package " + pkg + ";\n");
2.6 w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
2.7 - w.append("final class ").append(className).append(" {\n");
2.8 + w.append("public final class ").append(className).append(" {\n");
2.9 w.append(" private boolean locked;\n");
2.10 if (!initializeOnClick(className, (TypeElement) e, w, pp)) {
2.11 return false;
3.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Thu Mar 14 09:22:28 2013 +0100
3.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Mon Mar 18 17:17:00 2013 +0100
3.3 @@ -110,6 +110,10 @@
3.4
3.5 static class MockKnockout extends Knockout {
3.6 List<String> mutated = new ArrayList<String>();
3.7 +
3.8 + public MockKnockout() {
3.9 + super(new Object());
3.10 + }
3.11
3.12 @Override
3.13 public void valueHasMutated(String prop) {