With Batch update of models we are down to 1/6 of Java/JavaScript calls when building a chess board
1.1 --- a/json/src/main/java/org/apidesign/html/json/impl/Bindings.java Sat Aug 31 08:01:08 2013 +0000
1.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/Bindings.java Sat Aug 31 11:44:36 2013 +0000
1.3 @@ -32,36 +32,44 @@
1.4 * @author Jaroslav Tulach <jtulach@netbeans.org>
1.5 */
1.6 public final class Bindings<Data> {
1.7 - private final Data data;
1.8 + private Data data;
1.9 private final Technology<Data> bp;
1.10
1.11 - private Bindings(Data data, Technology<Data> bp) {
1.12 - this.data = data;
1.13 + private Bindings(Technology<Data> bp) {
1.14 this.bp = bp;
1.15 }
1.16
1.17 public <M> PropertyBinding registerProperty(String propName, M model, SetAndGet<M> access, boolean readOnly) {
1.18 - PropertyBinding pb = PropertyBindingAccessor.create(new PBData<M>(this, propName, model, access, readOnly));
1.19 - bp.bind(pb, model, data);
1.20 - return pb;
1.21 + return PropertyBindingAccessor.create(new PBData<M>(this, propName, model, access, readOnly));
1.22 }
1.23
1.24 public <M> FunctionBinding registerFunction(String name, M model, Callback<M> access) {
1.25 - FunctionBinding fb = PropertyBindingAccessor.createFunction(new FBData<M>(name, model, access));
1.26 - bp.expose(fb, model, data);
1.27 - return fb;
1.28 + return PropertyBindingAccessor.createFunction(new FBData<M>(name, model, access));
1.29 }
1.30
1.31 public static Bindings<?> apply(BrwsrCtx c, Object model) {
1.32 Technology<?> bp = JSON.findTechnology(c);
1.33 - return apply(bp, model);
1.34 + return apply(bp);
1.35 }
1.36
1.37 - private static <Data> Bindings<Data> apply(
1.38 - Technology<Data> bp, Object model
1.39 - ) {
1.40 - Data d = bp.wrapModel(model);
1.41 - return new Bindings<Data>(d, bp);
1.42 + private static <Data> Bindings<Data> apply(Technology<Data> bp) {
1.43 + return new Bindings<Data>(bp);
1.44 + }
1.45 +
1.46 + public final void finish(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
1.47 + assert data == null;
1.48 + if (bp instanceof Technology.BatchInit) {
1.49 + Technology.BatchInit<Data> bi = (Technology.BatchInit<Data>)bp;
1.50 + data = bi.wrapModel(model, propArr, funcArr);
1.51 + } else {
1.52 + data = bp.wrapModel(model);
1.53 + for (PropertyBinding b : propArr) {
1.54 + bp.bind(b, model, data);
1.55 + }
1.56 + for (FunctionBinding b : funcArr) {
1.57 + bp.expose(b, model, data);
1.58 + }
1.59 + }
1.60 }
1.61
1.62
2.1 --- a/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java Sat Aug 31 08:01:08 2013 +0000
2.2 +++ b/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java Sat Aug 31 11:44:36 2013 +0000
2.3 @@ -251,14 +251,23 @@
2.4 w.append(" private org.apidesign.html.json.impl.Bindings intKnckt() {\n");
2.5 w.append(" if (ko != null) return ko;\n");
2.6 w.append(" ko = org.apidesign.html.json.impl.Bindings.apply(context, this);\n");
2.7 - for (int i = 0; i < propsGetSet.size(); i += 5) {
2.8 - w.append(" ko.registerProperty(\"").append(propsGetSet.get(i)).append("\", this, new P(");
2.9 - w.append((i / 5) + "), " + (propsGetSet.get(i + 2) == null) + ");\n");
2.10 + {
2.11 + w.append(" org.apidesign.html.json.spi.PropertyBinding[] propArr = {\n");
2.12 + for (int i = 0; i < propsGetSet.size(); i += 5) {
2.13 + w.append(" ko.registerProperty(\"").append(propsGetSet.get(i)).append("\", this, new P(");
2.14 + w.append((i / 5) + "), " + (propsGetSet.get(i + 2) == null) + "),\n");
2.15 + }
2.16 + w.append(" };\n");
2.17 }
2.18 - for (int i = 0; i < functions.size(); i += 2) {
2.19 - w.append(" ko.registerFunction(\"").append(functions.get(i)).append("\", this, new P(");
2.20 - w.append((i / 2) + "));\n");
2.21 + {
2.22 + w.append(" org.apidesign.html.json.spi.FunctionBinding[] funcArr = {\n");
2.23 + for (int i = 0; i < functions.size(); i += 2) {
2.24 + w.append(" ko.registerFunction(\"").append(functions.get(i)).append("\", this, new P(");
2.25 + w.append((i / 2) + ")),\n");
2.26 + }
2.27 + w.append(" };\n");
2.28 }
2.29 + w.append(" ko.finish(this, propArr, funcArr);\n");
2.30 w.append(" return ko;\n");
2.31 w.append(" };\n");
2.32 w.append(" private static final class P implements org.apidesign.html.json.impl.SetAndGet<" + className + ">,\n");
3.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Technology.java Sat Aug 31 08:01:08 2013 +0000
3.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Technology.java Sat Aug 31 11:44:36 2013 +0000
3.3 @@ -87,4 +87,8 @@
3.4 * @param r the runnable to execute
3.5 */
3.6 public void runSafe(Runnable r);
3.7 +
3.8 + public static interface BatchInit<D> extends Technology<D> {
3.9 + public D wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr);
3.10 + }
3.11 }
4.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/Console.java Sat Aug 31 08:01:08 2013 +0000
4.2 +++ b/ko-fx/src/main/java/org/apidesign/html/kofx/Console.java Sat Aug 31 11:44:36 2013 +0000
4.3 @@ -20,6 +20,7 @@
4.4 */
4.5 package org.apidesign.html.kofx;
4.6
4.7 +import java.util.logging.Level;
4.8 import java.util.logging.Logger;
4.9 import net.java.html.js.JavaScriptBody;
4.10
4.11 @@ -31,25 +32,28 @@
4.12 *
4.13 * @author Jaroslav Tulach <jtulach@netbeans.org>
4.14 */
4.15 -public final class Console {
4.16 +final class Console {
4.17 private static final Logger LOG = Logger.getLogger(Console.class.getName());
4.18
4.19 private Console() {
4.20 }
4.21
4.22 static void register() {
4.23 - registerImpl(new Console());
4.24 + registerImpl("log", Level.INFO);
4.25 + registerImpl("info", Level.INFO);
4.26 + registerImpl("warn", Level.WARNING);
4.27 + registerImpl("error", Level.SEVERE);
4.28 }
4.29
4.30 - @JavaScriptBody(args = { "jconsole" }, body =
4.31 - "console.log = function(m) { jconsole.log(m); };" +
4.32 - "console.info = function(m) { jconsole.log(m); };" +
4.33 - "console.error = function(m) { jconsole.log(m); };" +
4.34 - "console.warn = function(m) { jconsole.log(m); };"
4.35 + @JavaScriptBody(args = { "attr", "l" },
4.36 + javacall = true, body =
4.37 + " window.console[attr] = function(m) {\n"
4.38 + + " @org.apidesign.html.kofx.Console::log(Ljava/util/logging/Level;Ljava/lang/String;)(l, m);\n"
4.39 + + " };\n"
4.40 )
4.41 - private static native void registerImpl(Console c);
4.42 + private static native void registerImpl(String attr, Level l);
4.43
4.44 - public void log(String msg) {
4.45 - LOG.info(msg);
4.46 + static void log(Level l, String msg) {
4.47 + LOG.log(l, msg);
4.48 }
4.49 }
5.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/FXContext.java Sat Aug 31 08:01:08 2013 +0000
5.2 +++ b/ko-fx/src/main/java/org/apidesign/html/kofx/FXContext.java Sat Aug 31 11:44:36 2013 +0000
5.3 @@ -46,7 +46,7 @@
5.4 */
5.5 @ServiceProvider(service = Contexts.Provider.class)
5.6 public final class FXContext
5.7 -implements Technology<JSObject>, Transfer, Contexts.Provider, WSTransfer<LoadWS> {
5.8 +implements Technology.BatchInit<JSObject>, Transfer, Contexts.Provider, WSTransfer<LoadWS> {
5.9 static final Logger LOG = Logger.getLogger(FXContext.class.getName());
5.10 private static Boolean javaScriptEnabled;
5.11
5.12 @@ -77,6 +77,22 @@
5.13 return LoadWS.isSupported();
5.14 }
5.15
5.16 +
5.17 + @Override
5.18 + public JSObject wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
5.19 + String[] propNames = new String[propArr.length];
5.20 + boolean[] propReadOnly = new boolean[propArr.length];
5.21 + for (int i = 0; i < propNames.length; i++) {
5.22 + propNames[i] = propArr[i].getPropertyName();
5.23 + propReadOnly[i] = propArr[i].isReadOnly();
5.24 + }
5.25 + String[] funcNames = new String[funcArr.length];
5.26 + for (int i = 0; i < funcNames.length; i++) {
5.27 + funcNames[i] = funcArr[i].getFunctionName();
5.28 + }
5.29 + return Knockout.wrapModel(model, propNames, propReadOnly, propArr, funcNames, funcArr);
5.30 + }
5.31 +
5.32 @Override
5.33 public JSObject wrapModel(Object model) {
5.34 JSObject obj = (JSObject) Knockout.createBinding(model).koData();
6.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/Knockout.java Sat Aug 31 08:01:08 2013 +0000
6.2 +++ b/ko-fx/src/main/java/org/apidesign/html/kofx/Knockout.java Sat Aug 31 11:44:36 2013 +0000
6.3 @@ -20,10 +20,6 @@
6.4 */
6.5 package org.apidesign.html.kofx;
6.6
6.7 -import java.io.BufferedReader;
6.8 -import java.io.IOException;
6.9 -import java.io.InputStream;
6.10 -import java.io.InputStreamReader;
6.11 import java.util.logging.Level;
6.12 import java.util.logging.Logger;
6.13 import net.java.html.js.JavaScriptBody;
6.14 @@ -67,15 +63,26 @@
6.15 return new Knockout(bindings);
6.16 }
6.17
6.18 + static JSObject wrapModel(
6.19 + Object model,
6.20 + String[] propNames, boolean[] propReadOnly, PropertyBinding[] propArr,
6.21 + String[] funcNames, FunctionBinding[] funcArr
6.22 + ) {
6.23 + return InvokeJS.wrapModel(model, propNames, propReadOnly, propArr, funcNames, funcArr);
6.24 + }
6.25 +
6.26 +
6.27 public void valueHasMutated(String prop) {
6.28 valueHasMutated((JSObject) model, prop);
6.29 }
6.30 public static void valueHasMutated(JSObject model, String prop) {
6.31 LOG.log(Level.FINE, "property mutated: {0}", prop);
6.32 try {
6.33 + if (model != null) {
6.34 Object koProp = model.getMember(prop);
6.35 - if (koProp instanceof JSObject) {
6.36 - ((JSObject)koProp).call("valueHasMutated");
6.37 + if (koProp instanceof JSObject) {
6.38 + ((JSObject)koProp).call("valueHasMutated");
6.39 + }
6.40 }
6.41 } catch (Throwable t) {
6.42 LOG.log(Level.WARNING, "valueHasMutated failed for " + model + " prop: " + prop, t);
6.43 @@ -127,6 +134,51 @@
6.44 )
6.45 private static native Object kObj();
6.46
6.47 + @JavaScriptBody(
6.48 + javacall = true,
6.49 + args = {"model", "propNames", "propReadOnly", "propArr", "funcNames", "funcArr"},
6.50 + body
6.51 + = "var ret = {};\n"
6.52 + + "ret['ko-fx.model'] = model;\n"
6.53 + + "function koComputed(name, readOnly, prop) {\n"
6.54 + + " var bnd = {"
6.55 + + " read: function() {"
6.56 + + " try {"
6.57 + + " var v = prop.@org.apidesign.html.json.spi.PropertyBinding::getValue()();"
6.58 + + " return v;"
6.59 + + " } catch (e) {"
6.60 + + " alert(\"Cannot call getValue on \" + model + \" prop: \" + name + \" error: \" + e);"
6.61 + + " }"
6.62 + + " },"
6.63 + + " owner: ret\n"
6.64 + + " };\n"
6.65 + + " if (!readOnly) {\n"
6.66 + + " bnd.write = function(val) {\n"
6.67 + + " prop.@org.apidesign.html.json.spi.PropertyBinding::setValue(Ljava/lang/Object;)(val);\n"
6.68 + + " };"
6.69 + + " };"
6.70 + + " ret[name] = ko.computed(bnd);"
6.71 + + "}\n"
6.72 + + "for (var i = 0; i < propNames.length; i++) {\n"
6.73 + + " koComputed(propNames[i], propReadOnly[i], propArr[i]);\n"
6.74 + + "}\n"
6.75 + + "function koExpose(name, func) {\n"
6.76 + + " ret[name] = function(data, ev) {\n"
6.77 + + " func.@org.apidesign.html.json.spi.FunctionBinding::call(Ljava/lang/Object;Ljava/lang/Object;)(data, ev);\n"
6.78 + + " };\n"
6.79 + + "}\n"
6.80 + + "for (var i = 0; i < funcNames.length; i++) {\n"
6.81 + + " koExpose(funcNames[i], funcArr[i]);\n"
6.82 + + "}\n"
6.83 + + "return ret;\n"
6.84 + )
6.85 + static native JSObject wrapModel(
6.86 + Object model,
6.87 + String[] propNames, boolean[] propReadOnly, PropertyBinding[] propArr,
6.88 + String[] funcNames, FunctionBinding[] funcArr
6.89 + );
6.90 +
6.91 +
6.92 @JavaScriptBody(args = { "value", "cnt " }, body =
6.93 " var ret = {};"
6.94 /* + " ret.toString = function() { return 'KObject' + cnt + ' value: ' + value + ' props: ' + Object.keys(this); }; " */