1.1 --- a/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Tue Sep 25 09:08:39 2012 +0200
1.2 +++ b/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Tue Sep 25 09:55:34 2012 +0200
1.3 @@ -28,11 +28,15 @@
1.4 import javax.annotation.processing.RoundEnvironment;
1.5 import javax.annotation.processing.SupportedAnnotationTypes;
1.6 import javax.lang.model.element.Element;
1.7 +import javax.lang.model.element.ElementKind;
1.8 +import javax.lang.model.element.ExecutableElement;
1.9 +import javax.lang.model.element.Modifier;
1.10 import javax.lang.model.element.PackageElement;
1.11 import javax.lang.model.element.TypeElement;
1.12 import javax.tools.Diagnostic;
1.13 import javax.tools.FileObject;
1.14 import javax.tools.StandardLocation;
1.15 +import org.apidesign.bck2brwsr.htmlpage.api.OnClick;
1.16 import org.apidesign.bck2brwsr.htmlpage.api.Page;
1.17 import org.openide.util.lookup.ServiceProvider;
1.18
1.19 @@ -42,7 +46,10 @@
1.20 * @author Jaroslav Tulach <jtulach@netbeans.org>
1.21 */
1.22 @ServiceProvider(service=Processor.class)
1.23 -@SupportedAnnotationTypes("org.apidesign.bck2brwsr.htmlpage.api.Page")
1.24 +@SupportedAnnotationTypes({
1.25 + "org.apidesign.bck2brwsr.htmlpage.api.Page",
1.26 + "org.apidesign.bck2brwsr.htmlpage.api.OnClick"
1.27 +})
1.28 public final class PageProcessor extends AbstractProcessor {
1.29 @Override
1.30 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
1.31 @@ -64,18 +71,26 @@
1.32 try {
1.33 FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + p.name(), e);
1.34 w = new OutputStreamWriter(java.openOutputStream());
1.35 - w.append("package " + pkg + ";\n");
1.36 - w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
1.37 - w.append("class ").append(p.name()).append(" {\n");
1.38 - for (String id : pp.ids()) {
1.39 - String tag = pp.tagNameForId(id);
1.40 - String type = type(tag);
1.41 - w.append(" ").append("public static final ").
1.42 - append(type).append(' ').append(cnstnt(id)).append(" = new ").
1.43 - append(type).append("(\"").append(id).append("\");\n");
1.44 + try {
1.45 + w.append("package " + pkg + ";\n");
1.46 + w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
1.47 + w.append("class ").append(p.name()).append(" {\n");
1.48 + for (String id : pp.ids()) {
1.49 + String tag = pp.tagNameForId(id);
1.50 + String type = type(tag);
1.51 + w.append(" ").append("public static final ").
1.52 + append(type).append(' ').append(cnstnt(id)).append(" = new ").
1.53 + append(type).append("(\"").append(id).append("\");\n");
1.54 + }
1.55 + w.append(" static {\n");
1.56 + if (!initializeOnClick(pe, w, pp)) {
1.57 + return false;
1.58 + }
1.59 + w.append(" }\n");
1.60 + w.append("}\n");
1.61 + } finally {
1.62 + w.close();
1.63 }
1.64 - w.append("}");
1.65 - w.close();
1.66 } catch (IOException ex) {
1.67 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Can't create " + p.name() + ".java", e);
1.68 return false;
1.69 @@ -110,4 +125,41 @@
1.70 private static String cnstnt(String id) {
1.71 return id.toUpperCase(Locale.ENGLISH).replace('.', '_');
1.72 }
1.73 +
1.74 + private boolean initializeOnClick(PackageElement pe, Writer w, ProcessPage pp) throws IOException {
1.75 + for (Element clazz : pe.getEnclosedElements()) {
1.76 + if (clazz.getKind() != ElementKind.CLASS) {
1.77 + continue;
1.78 + }
1.79 + TypeElement type = (TypeElement)clazz;
1.80 + for (Element method : clazz.getEnclosedElements()) {
1.81 + OnClick oc = method.getAnnotation(OnClick.class);
1.82 + if (oc != null) {
1.83 + if (pp.tagNameForId(oc.id()) == null) {
1.84 + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "id = " + oc.id() + " does not exist in the HTML page. Found only " + pp.ids(), method);
1.85 + return false;
1.86 + }
1.87 + ExecutableElement ee = (ExecutableElement)method;
1.88 + if (!ee.getParameters().isEmpty()) {
1.89 + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@OnClose method can't take arguments", ee);
1.90 + return false;
1.91 + }
1.92 + if (!ee.getModifiers().contains(Modifier.STATIC)) {
1.93 + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@OnClose method has to be static", ee);
1.94 + return false;
1.95 + }
1.96 + if (ee.getModifiers().contains(Modifier.PRIVATE)) {
1.97 + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@OnClose method can't be private", ee);
1.98 + return false;
1.99 + }
1.100 + w.append(" ").append(cnstnt(oc.id())).
1.101 + append(".addOnClick(new Runnable() { public void run() {\n");
1.102 + w.append(" ").append(type.getSimpleName().toString()).
1.103 + append('.').append(ee.getSimpleName()).append("();\n");
1.104 + w.append(" }});\n");
1.105 + }
1.106 + }
1.107 + }
1.108 + return true;
1.109 + }
1.110 }
2.1 --- a/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Tue Sep 25 09:08:39 2012 +0200
2.2 +++ b/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Tue Sep 25 09:55:34 2012 +0200
2.3 @@ -33,4 +33,12 @@
2.4 static void setAttribute(Element el, String property, Object value) {
2.5 throw new UnsupportedOperationException("Needs JavaScript!");
2.6 }
2.7 +
2.8 + /** Executes given runnable when user performs a "click" on the given
2.9 + * element.
2.10 + * @param r the runnable to execute, never null
2.11 + */
2.12 + public final void addOnClick(Runnable r) {
2.13 + throw new UnsupportedOperationException("Needs JavaScript!");
2.14 + }
2.15 }
3.1 --- a/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.js Tue Sep 25 09:08:39 2012 +0200
3.2 +++ b/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.js Tue Sep 25 09:55:34 2012 +0200
3.3 @@ -4,3 +4,7 @@
3.4 document.getElementById(self.id)[property] = value;
3.5 }
3.6
3.7 +function org_apidesign_bck2brwsr_htmlpage_api_Element_addOnClick_Ljava_lang_Runnable(self, run) {
3.8 + document.getElementById(self.id).onClick = function() { run.runV(); };
3.9 +}
3.10 +
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnClick.java Tue Sep 25 09:55:34 2012 +0200
4.3 @@ -0,0 +1,21 @@
4.4 +/*
4.5 + * To change this template, choose Tools | Templates
4.6 + * and open the template in the editor.
4.7 + */
4.8 +package org.apidesign.bck2brwsr.htmlpage.api;
4.9 +
4.10 +import java.lang.annotation.ElementType;
4.11 +import java.lang.annotation.Retention;
4.12 +import java.lang.annotation.RetentionPolicy;
4.13 +import java.lang.annotation.Target;
4.14 +
4.15 +/** Adds an onClick handler to an element identified by given <em>id</em>.
4.16 + * Apply on a <code>public static void</code> method with no arguments.
4.17 + *
4.18 + * @author Jaroslav Tulach <jtulach@netbeans.org>
4.19 + */
4.20 +@Retention(RetentionPolicy.SOURCE)
4.21 +@Target(ElementType.METHOD)
4.22 +public @interface OnClick {
4.23 + String id();
4.24 +}
5.1 --- a/htmlpage/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Tue Sep 25 09:08:39 2012 +0200
5.2 +++ b/htmlpage/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Tue Sep 25 09:55:34 2012 +0200
5.3 @@ -43,4 +43,13 @@
5.4 void testWhetherWeCanCallTheGeneratedIdFields() {
5.5 Title t = TestPage.PG_TITLE;
5.6 }
5.7 +
5.8 + @OnClick(id="pg.button")
5.9 + static void handleButtonClick() {
5.10 +
5.11 + }
5.12 +
5.13 + @Test public void testOnclickHandlerGenerated() {
5.14 +
5.15 + }
5.16 }