@OnFunction can accept model classes model
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Sun, 31 Mar 2013 05:34:15 +0200
branchmodel
changeset 90622358b42ec2a
parent 905 98b20f45c515
child 907 5dc21ce7269d
@OnFunction can accept model classes
javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java
javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java
javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java
     1.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java	Sat Mar 30 07:58:50 2013 +0100
     1.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java	Sun Mar 31 05:34:15 2013 +0200
     1.3 @@ -41,6 +41,14 @@
     1.4          Object ret = getProperty(object, property);
     1.5          return ret instanceof Number ? ((Number)ret).intValue() : Integer.MIN_VALUE;
     1.6      }
     1.7 +
     1.8 +    public static <T> T toModel(Class<T> modelClass, Object object, String property) {
     1.9 +        Object ret = getProperty(object, property);
    1.10 +        if (ret == null || modelClass.isInstance(ret)) {
    1.11 +            return modelClass.cast(ret);
    1.12 +        }
    1.13 +        throw new IllegalStateException("Value " + ret + " is not of type " + modelClass);
    1.14 +    }
    1.15      
    1.16      @JavaScriptBody(args = { "object", "property" },
    1.17          body = "if (property === null) return object;\n"
     2.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java	Sat Mar 30 07:58:50 2013 +0100
     2.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java	Sun Mar 31 05:34:15 2013 +0200
     2.3 @@ -28,9 +28,9 @@
     2.4  import java.util.HashMap;
     2.5  import java.util.LinkedHashSet;
     2.6  import java.util.List;
     2.7 -import java.util.Locale;
     2.8  import java.util.Map;
     2.9  import java.util.Set;
    2.10 +import java.util.WeakHashMap;
    2.11  import javax.annotation.processing.AbstractProcessor;
    2.12  import javax.annotation.processing.Completion;
    2.13  import javax.annotation.processing.Completions;
    2.14 @@ -73,6 +73,7 @@
    2.15      "org.apidesign.bck2brwsr.htmlpage.api.On"
    2.16  })
    2.17  public final class PageProcessor extends AbstractProcessor {
    2.18 +    private final Map<Element,String> models = new WeakHashMap<>();
    2.19      @Override
    2.20      public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    2.21          boolean ok = true;
    2.22 @@ -86,6 +87,9 @@
    2.23                  ok = false;
    2.24              }
    2.25          }
    2.26 +        if (roundEnv.processingOver()) {
    2.27 +            models.clear();
    2.28 +        }
    2.29          return ok;
    2.30      }
    2.31  
    2.32 @@ -129,6 +133,7 @@
    2.33                  w.append("  private boolean locked;\n");
    2.34                  w.append("  private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n");
    2.35                  w.append(body.toString());
    2.36 +                w.append("  private static Class<" + e.getSimpleName() + "> modelFor() { return null; }\n");
    2.37                  w.append("}\n");
    2.38              } finally {
    2.39                  w.close();
    2.40 @@ -546,6 +551,7 @@
    2.41              if (m != null) {
    2.42                  ret = findPkgName(e) + '.' + m.className();
    2.43                  isModel = true;
    2.44 +                models.put(e, m.className());
    2.45              } else {
    2.46                  ret = tm.toString();
    2.47              }
    2.48 @@ -687,18 +693,21 @@
    2.49                      params.append('"').append(id).append('"');
    2.50                      continue;
    2.51                  }
    2.52 -                toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toString";
    2.53 +                toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toString(";
    2.54              }
    2.55              if (ve.asType().getKind() == TypeKind.DOUBLE) {
    2.56 -                toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toDouble";
    2.57 +                toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toDouble(";
    2.58              }
    2.59              if (ve.asType().getKind() == TypeKind.INT) {
    2.60 -                toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toInt";
    2.61 +                toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toInt(";
    2.62 +            }
    2.63 +            if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) {
    2.64 +                toCall = "org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toModel(" + ve.asType() + ".class, ";
    2.65              }
    2.66  
    2.67              if (toCall != null) {
    2.68 -                params.append(toCall).append('(');
    2.69 -                if (dataName != null && ve.getSimpleName().contentEquals("data")) {
    2.70 +                params.append(toCall);
    2.71 +                if (dataName != null && ve.getSimpleName().contentEquals(dataName)) {
    2.72                      params.append(dataName);
    2.73                      params.append(", null");
    2.74                  } else {
    2.75 @@ -726,4 +735,17 @@
    2.76          }
    2.77          return params;
    2.78      }
    2.79 +    
    2.80 +    private boolean isModel(TypeMirror tm) {
    2.81 +        final Element e = processingEnv.getTypeUtils().asElement(tm);
    2.82 +        for (Element ch : e.getEnclosedElements()) {
    2.83 +            if (ch.getKind() == ElementKind.METHOD) {
    2.84 +                ExecutableElement ee = (ExecutableElement)ch;
    2.85 +                if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) {
    2.86 +                    return true;
    2.87 +                }
    2.88 +            }
    2.89 +        }
    2.90 +        return models.values().contains(e.getSimpleName().toString());
    2.91 +    }
    2.92  }
     3.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java	Sat Mar 30 07:58:50 2013 +0100
     3.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java	Sun Mar 31 05:34:15 2013 +0200
     3.3 @@ -36,7 +36,8 @@
     3.4  @Page(xhtml="Knockout.xhtml", className="KnockoutModel", properties={
     3.5      @Property(name="name", type=String.class),
     3.6      @Property(name="results", type=String.class, array = true),
     3.7 -    @Property(name="callbackCount", type=int.class)
     3.8 +    @Property(name="callbackCount", type=int.class),
     3.9 +    @Property(name="people", type=PersonImpl.class, array = true)
    3.10  }) 
    3.11  public class KnockoutTest {
    3.12      
    3.13 @@ -98,11 +99,44 @@
    3.14          assert cnt == 2 : "Two children now, but was " + cnt;
    3.15      }
    3.16      
    3.17 +    @HtmlFragment(
    3.18 +        "<ul id='ul' data-bind='foreach: people'>\n"
    3.19 +        + "  <li data-bind='text: $data.firstName, click: $root.removePerson'></li>\n"
    3.20 +        + "</ul>\n"
    3.21 +    )
    3.22 +    @BrwsrTest public void displayContentOfArrayOfPeople() {
    3.23 +        KnockoutModel m = new KnockoutModel();
    3.24 +        m.getPeople().add(new Person());
    3.25 +        m.applyBindings();
    3.26 +        
    3.27 +        int cnt = countChildren("ul");
    3.28 +        assert cnt == 1 : "One child, but was " + cnt;
    3.29 +        
    3.30 +        m.getPeople().add(new Person());
    3.31 +
    3.32 +        cnt = countChildren("ul");
    3.33 +        assert cnt == 2 : "Two children now, but was " + cnt;
    3.34 +
    3.35 +        triggerChildClick("ul", 1);
    3.36 +        
    3.37 +        assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount();
    3.38 +
    3.39 +        cnt = countChildren("ul");
    3.40 +        assert cnt == 1 : "Again one child, but was " + cnt;
    3.41 +    }
    3.42 +     
    3.43      @OnFunction
    3.44      static void call(KnockoutModel m, String data) {
    3.45          m.setName(data);
    3.46          m.setCallbackCount(m.getCallbackCount() + 1);
    3.47      }
    3.48 +
    3.49 +    @OnFunction
    3.50 +    static void removePerson(KnockoutModel model, Person data) {
    3.51 +        model.setCallbackCount(model.getCallbackCount() + 1);
    3.52 +        model.getPeople().remove(data);
    3.53 +    }
    3.54 +    
    3.55      
    3.56      @ComputedProperty
    3.57      static String helloMessage(String name) {