# HG changeset patch # User Jaroslav Tulach # Date 1364700855 -7200 # Node ID 22358b42ec2ae1d12636c956423450ab337f5978 # Parent 98b20f45c515d9bdefd88b025904170ff31e65e8 @OnFunction can accept model classes diff -r 98b20f45c515 -r 22358b42ec2a javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java Sat Mar 30 07:58:50 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java Sun Mar 31 05:34:15 2013 +0200 @@ -41,6 +41,14 @@ Object ret = getProperty(object, property); return ret instanceof Number ? ((Number)ret).intValue() : Integer.MIN_VALUE; } + + public static T toModel(Class modelClass, Object object, String property) { + Object ret = getProperty(object, property); + if (ret == null || modelClass.isInstance(ret)) { + return modelClass.cast(ret); + } + throw new IllegalStateException("Value " + ret + " is not of type " + modelClass); + } @JavaScriptBody(args = { "object", "property" }, body = "if (property === null) return object;\n" diff -r 98b20f45c515 -r 22358b42ec2a javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Sat Mar 30 07:58:50 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Sun Mar 31 05:34:15 2013 +0200 @@ -28,9 +28,9 @@ import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.WeakHashMap; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Completion; import javax.annotation.processing.Completions; @@ -73,6 +73,7 @@ "org.apidesign.bck2brwsr.htmlpage.api.On" }) public final class PageProcessor extends AbstractProcessor { + private final Map models = new WeakHashMap<>(); @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { boolean ok = true; @@ -86,6 +87,9 @@ ok = false; } } + if (roundEnv.processingOver()) { + models.clear(); + } return ok; } @@ -129,6 +133,7 @@ w.append(" private boolean locked;\n"); w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n"); w.append(body.toString()); + w.append(" private static Class<" + e.getSimpleName() + "> modelFor() { return null; }\n"); w.append("}\n"); } finally { w.close(); @@ -546,6 +551,7 @@ if (m != null) { ret = findPkgName(e) + '.' + m.className(); isModel = true; + models.put(e, m.className()); } else { ret = tm.toString(); } @@ -687,18 +693,21 @@ params.append('"').append(id).append('"'); continue; } - toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toString"; + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toString("; } if (ve.asType().getKind() == TypeKind.DOUBLE) { - toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toDouble"; + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toDouble("; } if (ve.asType().getKind() == TypeKind.INT) { - toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toInt"; + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toInt("; + } + if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) { + toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toModel(" + ve.asType() + ".class, "; } if (toCall != null) { - params.append(toCall).append('('); - if (dataName != null && ve.getSimpleName().contentEquals("data")) { + params.append(toCall); + if (dataName != null && ve.getSimpleName().contentEquals(dataName)) { params.append(dataName); params.append(", null"); } else { @@ -726,4 +735,17 @@ } return params; } + + private boolean isModel(TypeMirror tm) { + final Element e = processingEnv.getTypeUtils().asElement(tm); + for (Element ch : e.getEnclosedElements()) { + if (ch.getKind() == ElementKind.METHOD) { + ExecutableElement ee = (ExecutableElement)ch; + if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) { + return true; + } + } + } + return models.values().contains(e.getSimpleName().toString()); + } } diff -r 98b20f45c515 -r 22358b42ec2a javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java Sat Mar 30 07:58:50 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java Sun Mar 31 05:34:15 2013 +0200 @@ -36,7 +36,8 @@ @Page(xhtml="Knockout.xhtml", className="KnockoutModel", properties={ @Property(name="name", type=String.class), @Property(name="results", type=String.class, array = true), - @Property(name="callbackCount", type=int.class) + @Property(name="callbackCount", type=int.class), + @Property(name="people", type=PersonImpl.class, array = true) }) public class KnockoutTest { @@ -98,11 +99,44 @@ assert cnt == 2 : "Two children now, but was " + cnt; } + @HtmlFragment( + "
    \n" + + "
  • \n" + + "
\n" + ) + @BrwsrTest public void displayContentOfArrayOfPeople() { + KnockoutModel m = new KnockoutModel(); + m.getPeople().add(new Person()); + m.applyBindings(); + + int cnt = countChildren("ul"); + assert cnt == 1 : "One child, but was " + cnt; + + m.getPeople().add(new Person()); + + cnt = countChildren("ul"); + assert cnt == 2 : "Two children now, but was " + cnt; + + triggerChildClick("ul", 1); + + assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount(); + + cnt = countChildren("ul"); + assert cnt == 1 : "Again one child, but was " + cnt; + } + @OnFunction static void call(KnockoutModel m, String data) { m.setName(data); m.setCallbackCount(m.getCallbackCount() + 1); } + + @OnFunction + static void removePerson(KnockoutModel model, Person data) { + model.setCallbackCount(model.getCallbackCount() + 1); + model.getPeople().remove(data); + } + @ComputedProperty static String helloMessage(String name) {