Precompute property values in Java, so ko.computed does not need to call back from JavaScript to get initial value.
1.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/FXContext.java Sun Sep 01 06:52:02 2013 +0000
1.2 +++ b/ko-fx/src/main/java/org/apidesign/html/kofx/FXContext.java Sun Sep 01 07:13:38 2013 +0000
1.3 @@ -82,15 +82,21 @@
1.4 public JSObject wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
1.5 String[] propNames = new String[propArr.length];
1.6 boolean[] propReadOnly = new boolean[propArr.length];
1.7 + Object[] propValues = new Object[propArr.length];
1.8 for (int i = 0; i < propNames.length; i++) {
1.9 propNames[i] = propArr[i].getPropertyName();
1.10 propReadOnly[i] = propArr[i].isReadOnly();
1.11 + propValues[i] = propArr[i].getValue();
1.12 }
1.13 String[] funcNames = new String[funcArr.length];
1.14 for (int i = 0; i < funcNames.length; i++) {
1.15 funcNames[i] = funcArr[i].getFunctionName();
1.16 }
1.17 - return Knockout.wrapModel(model, propNames, propReadOnly, propArr, funcNames, funcArr);
1.18 +
1.19 + return Knockout.wrapModel(model,
1.20 + propNames, propReadOnly, Knockout.toArray(propValues), propArr,
1.21 + funcNames, funcArr
1.22 + );
1.23 }
1.24
1.25 @Override
2.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/Knockout.java Sun Sep 01 06:52:02 2013 +0000
2.2 +++ b/ko-fx/src/main/java/org/apidesign/html/kofx/Knockout.java Sun Sep 01 07:13:38 2013 +0000
2.3 @@ -73,19 +73,25 @@
2.4
2.5 @JavaScriptBody(
2.6 javacall = true,
2.7 - args = {"model", "propNames", "propReadOnly", "propArr", "funcNames", "funcArr"},
2.8 + args = {"model", "propNames", "propReadOnly", "propValues", "propArr", "funcNames", "funcArr"},
2.9 body
2.10 = "var ret = {};\n"
2.11 + "ret['ko-fx.model'] = model;\n"
2.12 - + "function koComputed(name, readOnly, prop) {\n"
2.13 + + "function koComputed(name, readOnly, value, prop) {\n"
2.14 + + " function realGetter() {\n"
2.15 + + " try {"
2.16 + + " var v = prop.@org.apidesign.html.json.spi.PropertyBinding::getValue()();"
2.17 + + " return v;"
2.18 + + " } catch (e) {"
2.19 + + " alert(\"Cannot call getValue on \" + model + \" prop: \" + name + \" error: \" + e);"
2.20 + + " }"
2.21 + + " }\n"
2.22 + + " var activeGetter = function() { return value; };\n"
2.23 + " var bnd = {"
2.24 + " read: function() {"
2.25 - + " try {"
2.26 - + " var v = prop.@org.apidesign.html.json.spi.PropertyBinding::getValue()();"
2.27 - + " return v;"
2.28 - + " } catch (e) {"
2.29 - + " alert(\"Cannot call getValue on \" + model + \" prop: \" + name + \" error: \" + e);"
2.30 - + " }"
2.31 + + " var r = activeGetter();"
2.32 + + " activeGetter = realGetter;"
2.33 + + " return r;"
2.34 + " },"
2.35 + " owner: ret\n"
2.36 + " };\n"
2.37 @@ -97,7 +103,7 @@
2.38 + " ret[name] = ko.computed(bnd);"
2.39 + "}\n"
2.40 + "for (var i = 0; i < propNames.length; i++) {\n"
2.41 - + " koComputed(propNames[i], propReadOnly[i], propArr[i]);\n"
2.42 + + " koComputed(propNames[i], propReadOnly[i], propValues[i], propArr[i]);\n"
2.43 + "}\n"
2.44 + "function koExpose(name, func) {\n"
2.45 + " ret[name] = function(data, ev) {\n"
2.46 @@ -111,7 +117,7 @@
2.47 )
2.48 static native JSObject wrapModel(
2.49 Object model,
2.50 - String[] propNames, boolean[] propReadOnly, PropertyBinding[] propArr,
2.51 + String[] propNames, boolean[] propReadOnly, Object propValues, PropertyBinding[] propArr,
2.52 String[] funcNames, FunctionBinding[] funcArr
2.53 );
2.54 }
3.1 --- a/ko-fx/src/test/java/org/apidesign/html/kofx/KnockoutFXTest.java Sun Sep 01 06:52:02 2013 +0000
3.2 +++ b/ko-fx/src/test/java/org/apidesign/html/kofx/KnockoutFXTest.java Sun Sep 01 07:13:38 2013 +0000
3.3 @@ -86,16 +86,22 @@
3.4 List<Object> res = new ArrayList<Object>();
3.5 for (int i = 0; i < arr.length; i++) {
3.6 Class<?> c = Class.forName(arr[i].getName(), true, l);
3.7 - Class<? extends Annotation> koTest =
3.8 - c.getClassLoader().loadClass(KOTest.class.getName()).
3.9 - asSubclass(Annotation.class);
3.10 - for (Method m : c.getMethods()) {
3.11 - if (m.getAnnotation(koTest) != null) {
3.12 - res.add(new KOFx(m));
3.13 - }
3.14 + seekKOTests(c, res);
3.15 + }
3.16 + Class<?> c = Class.forName(LessCallbacksCheck.class.getName(), true, l);
3.17 + seekKOTests(c, res);
3.18 + return res.toArray();
3.19 + }
3.20 +
3.21 + private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
3.22 + Class<? extends Annotation> koTest =
3.23 + c.getClassLoader().loadClass(KOTest.class.getName()).
3.24 + asSubclass(Annotation.class);
3.25 + for (Method m : c.getMethods()) {
3.26 + if (m.getAnnotation(koTest) != null) {
3.27 + res.add(new KOFx(m));
3.28 }
3.29 }
3.30 - return res.toArray();
3.31 }
3.32
3.33 static synchronized ClassLoader getClassLoader() throws InterruptedException {
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/ko-fx/src/test/java/org/apidesign/html/kofx/LessCallbacksCheck.java Sun Sep 01 07:13:38 2013 +0000
4.3 @@ -0,0 +1,60 @@
4.4 +/**
4.5 + * HTML via Java(tm) Language Bindings
4.6 + * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
4.7 + *
4.8 + * This program is free software: you can redistribute it and/or modify
4.9 + * it under the terms of the GNU General Public License as published by
4.10 + * the Free Software Foundation, version 2 of the License.
4.11 + *
4.12 + * This program is distributed in the hope that it will be useful,
4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.15 + * GNU General Public License for more details. apidesign.org
4.16 + * designates this particular file as subject to the
4.17 + * "Classpath" exception as provided by apidesign.org
4.18 + * in the License file that accompanied this code.
4.19 + *
4.20 + * You should have received a copy of the GNU General Public License
4.21 + * along with this program. Look for COPYING file in the top folder.
4.22 + * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
4.23 + */
4.24 +package org.apidesign.html.kofx;
4.25 +
4.26 +import java.io.PrintWriter;
4.27 +import java.io.StringWriter;
4.28 +import net.java.html.json.ComputedProperty;
4.29 +import net.java.html.json.Model;
4.30 +import net.java.html.json.Property;
4.31 +import org.apidesign.html.json.tck.KOTest;
4.32 +
4.33 +/**
4.34 + *
4.35 + * @author Jaroslav Tulach <jtulach@netbeans.org>
4.36 + */
4.37 +@Model(className = "LessCalls", properties = {
4.38 + @Property(name = "value", type = int.class)
4.39 +})
4.40 +public class LessCallbacksCheck {
4.41 + private static StringWriter sw;
4.42 +
4.43 + @ComputedProperty static int plusOne(int value) {
4.44 + if (sw == null) {
4.45 + sw = new StringWriter();
4.46 + }
4.47 + new Exception("Who calls me?").printStackTrace(
4.48 + new PrintWriter(sw)
4.49 + );
4.50 + return value + 1;
4.51 + }
4.52 +
4.53 + @KOTest public void dontCallForInitialValueBackToJavaVM() {
4.54 + LessCalls m = new LessCalls(10).applyBindings();
4.55 + assert m.getPlusOne() == 11 : "Expecting 11: " + m.getPlusOne();
4.56 +
4.57 + assert sw != null : "StringWriter should be initialized: " + sw;
4.58 +
4.59 + if (sw.toString().contains("$JsCallbacks$")) {
4.60 + assert false : "Don't call for initial value via JsCallbacks:\n" + sw;
4.61 + }
4.62 + }
4.63 +}