Support for event parameters for methods annotated by @On(event). Basic idea by me, tests provided by Toni. Thanks a lot.
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 05 Mar 2013 19:00:36 +0100
changeset 8132fa85847ccf7
parent 812 2108bb8770a5
child 814 0099855f7ee8
Support for event parameters for methods annotated by @On(event). Basic idea by me, tests provided by Toni. Thanks a lot.
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/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java
javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java
javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnHandler.java
javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java
javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java
javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java	Tue Mar 05 19:00:36 2013 +0100
     1.3 @@ -0,0 +1,51 @@
     1.4 +/**
     1.5 + * Back 2 Browser Bytecode Translator
     1.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     1.7 + *
     1.8 + * This program is free software: you can redistribute it and/or modify
     1.9 + * it under the terms of the GNU General Public License as published by
    1.10 + * the Free Software Foundation, version 2 of the License.
    1.11 + *
    1.12 + * This program is distributed in the hope that it will be useful,
    1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 + * GNU General Public License for more details.
    1.16 + *
    1.17 + * You should have received a copy of the GNU General Public License
    1.18 + * along with this program. Look for COPYING file in the top folder.
    1.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    1.20 + */
    1.21 +package org.apidesign.bck2brwsr.htmlpage;
    1.22 +
    1.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    1.24 +
    1.25 +/**
    1.26 + *
    1.27 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    1.28 + */
    1.29 +public final class ConvertTypes {
    1.30 +    ConvertTypes() {
    1.31 +    }
    1.32 +    
    1.33 +    public static String toString(Object object, String property) {
    1.34 +        Object ret = getProperty(object, property);
    1.35 +        return ret == null ? null : ret.toString();
    1.36 +    }
    1.37 +
    1.38 +    public static double toDouble(Object object, String property) {
    1.39 +        Object ret = getProperty(object, property);
    1.40 +        return ret instanceof Number ? ((Number)ret).doubleValue() : Double.NaN;
    1.41 +    }
    1.42 +
    1.43 +    public static int toInt(Object object, String property) {
    1.44 +        Object ret = getProperty(object, property);
    1.45 +        return ret instanceof Number ? ((Number)ret).intValue() : Integer.MIN_VALUE;
    1.46 +    }
    1.47 +    
    1.48 +    @JavaScriptBody(args = { "object", "property" },
    1.49 +        body = "var p = object[property]; return p ? p : null;"
    1.50 +    )
    1.51 +    private static Object getProperty(Object object, String property) {
    1.52 +        return null;
    1.53 +    }
    1.54 +}
     2.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java	Tue Mar 05 18:47:29 2013 +0100
     2.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java	Tue Mar 05 19:00:36 2013 +0100
     2.3 @@ -45,6 +45,7 @@
     2.4  import javax.lang.model.element.TypeElement;
     2.5  import javax.lang.model.element.VariableElement;
     2.6  import javax.lang.model.type.MirroredTypeException;
     2.7 +import javax.lang.model.type.TypeKind;
     2.8  import javax.lang.model.type.TypeMirror;
     2.9  import javax.tools.Diagnostic;
    2.10  import javax.tools.FileObject;
    2.11 @@ -209,7 +210,19 @@
    2.12                                  }
    2.13                                  first = false;
    2.14                                  if (ve.asType() == stringType) {
    2.15 -                                    params.append('"').append(id).append('"');
    2.16 +                                    if (ve.getSimpleName().contentEquals("id")) {
    2.17 +                                        params.append('"').append(id).append('"');
    2.18 +                                        continue;
    2.19 +                                    }
    2.20 +                                    params.append("org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toString(ev, \"");
    2.21 +                                    params.append(ve.getSimpleName().toString());
    2.22 +                                    params.append("\")");
    2.23 +                                    continue;
    2.24 +                                }
    2.25 +                                if (processingEnv.getTypeUtils().getPrimitiveType(TypeKind.DOUBLE) == ve.asType()) {
    2.26 +                                    params.append("org.apidesign.bck2brwsr.htmlpage.ConvertTypes.toDouble(ev, \"");
    2.27 +                                    params.append(ve.getSimpleName().toString());
    2.28 +                                    params.append("\")");
    2.29                                      continue;
    2.30                                  }
    2.31                                  String rn = ve.asType().toString();
    2.32 @@ -222,7 +235,7 @@
    2.33                                      continue;
    2.34                                  }
    2.35                                  processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 
    2.36 -                                    "@On method can only accept String or " + className + " arguments",
    2.37 +                                    "@On method can only accept String named 'id' or " + className + " arguments",
    2.38                                      ee
    2.39                                  );
    2.40                                  return false;
    2.41 @@ -252,10 +265,10 @@
    2.42              }
    2.43              w.append("  }\n");
    2.44              if (dispatchCnt > 0) {
    2.45 -                w.append("class OnDispatch implements Runnable {\n");
    2.46 +                w.append("class OnDispatch implements OnHandler {\n");
    2.47                  w.append("  private final int dispatch;\n");
    2.48                  w.append("  OnDispatch(int d) { dispatch = d; }\n");
    2.49 -                w.append("  public void run() {\n");
    2.50 +                w.append("  public void onEvent(Object ev) {\n");
    2.51                  w.append("    switch (dispatch) {\n");
    2.52                  w.append(dispatch);
    2.53                  w.append("    }\n");
     3.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java	Tue Mar 05 18:47:29 2013 +0100
     3.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java	Tue Mar 05 19:00:36 2013 +0100
     3.3 @@ -61,14 +61,18 @@
     3.4      
     3.5      /** Executes given runnable when user performs a "click" on the given
     3.6       * element.
     3.7 +     * @param data an array of one element to fill with event parameter (if any)
     3.8       * @param r the runnable to execute, never null
     3.9       */
    3.10      @JavaScriptBody(
    3.11          args={ "ev", "r" },
    3.12          body="var e = window.document.getElementById(this._id());\n"
    3.13 -           + "e[ev._id()] = function() { r.run__V(); };\n"
    3.14 +           + "e[ev._id()] = function(ev) {\n"
    3.15 +        + "  var d = ev ? ev : null;\n"
    3.16 +        + "  r.onEvent__VLjava_lang_Object_2(d);\n"
    3.17 +        + "};\n"
    3.18      )
    3.19 -    final void on(OnEvent ev, Runnable r) {
    3.20 +    final void on(OnEvent ev, OnHandler r) {
    3.21      }
    3.22  
    3.23      /** Shows alert message dialog in a browser.
     4.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java	Tue Mar 05 18:47:29 2013 +0100
     4.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnController.java	Tue Mar 05 19:00:36 2013 +0100
     4.3 @@ -30,14 +30,33 @@
     4.4          this.arr = arr;
     4.5      }
     4.6      
     4.7 +    /** Registers an event handler on associated {@link OnEvent}
     4.8 +     * and {@link Element}
     4.9 +     * 
    4.10 +     * @param handler the handler to be called when the event occurs
    4.11 +     */
    4.12 +    public void perform(final OnHandler handler) {
    4.13 +        for (Element e : arr) {
    4.14 +            e.on(event, handler);
    4.15 +        }
    4.16 +    }
    4.17 +    
    4.18      /** Registers a runnable to be performed on associated {@link OnEvent} 
    4.19       * and {@link Element}.
    4.20       * 
    4.21       * @see OnEvent#of
    4.22       */
    4.23 -    public void perform(Runnable r) {
    4.24 +    public void perform(final Runnable r) {
    4.25 +        class W implements OnHandler {
    4.26 +            @Override
    4.27 +            public void onEvent(Object event) throws Exception {
    4.28 +                r.run();
    4.29 +            }
    4.30 +        }
    4.31 +        perform(new W());
    4.32 +        OnHandler w = new W();
    4.33          for (Element e : arr) {
    4.34 -            e.on(event, r);
    4.35 +            e.on(event, w);
    4.36          }
    4.37      }
    4.38  }
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnHandler.java	Tue Mar 05 19:00:36 2013 +0100
     5.3 @@ -0,0 +1,33 @@
     5.4 +/**
     5.5 + * Back 2 Browser Bytecode Translator
     5.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     5.7 + *
     5.8 + * This program is free software: you can redistribute it and/or modify
     5.9 + * it under the terms of the GNU General Public License as published by
    5.10 + * the Free Software Foundation, version 2 of the License.
    5.11 + *
    5.12 + * This program is distributed in the hope that it will be useful,
    5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.15 + * GNU General Public License for more details.
    5.16 + *
    5.17 + * You should have received a copy of the GNU General Public License
    5.18 + * along with this program. Look for COPYING file in the top folder.
    5.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    5.20 + */
    5.21 +package org.apidesign.bck2brwsr.htmlpage.api;
    5.22 +
    5.23 +/** Handler to be called when an event in an HTML {@link Page} appears.
    5.24 + * @see OnEvent
    5.25 + * @see OnController
    5.26 + *
    5.27 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    5.28 + */
    5.29 +public interface OnHandler {
    5.30 +    /** Called when a DOM event appears
    5.31 +     * 
    5.32 +     * @param event the event as produced by the browser
    5.33 +     * @throws Exception execution can throw exception
    5.34 +     */
    5.35 +    public void onEvent(Object event) throws Exception;
    5.36 +}
     6.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java	Tue Mar 05 18:47:29 2013 +0100
     6.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java	Tue Mar 05 19:00:36 2013 +0100
     6.3 @@ -60,4 +60,9 @@
     6.4          }
     6.5          PAGE.PG_TITLE.setText(id);
     6.6      }
     6.7 +    
     6.8 +    @On(event = CLICK, id={ "pg.canvas" })
     6.9 +    static void clickCanvas(String id, double layerX) {
    6.10 +        PAGE.PG_CANVAS.setWidth((int) layerX);
    6.11 +    }
    6.12  }
     7.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java	Tue Mar 05 18:47:29 2013 +0100
     7.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java	Tue Mar 05 19:00:36 2013 +0100
     7.3 @@ -36,11 +36,12 @@
     7.4          assertNotNull(is, "Sample HTML page found");
     7.5          ProcessPage res = ProcessPage.readPage(is);
     7.6          final Set<String> ids = res.ids();
     7.7 -        assertEquals(ids.size(), 3, "Three ids found: " + ids);
     7.8 +        assertEquals(ids.size(), 4, "Four ids found: " + ids);
     7.9          
    7.10          assertEquals(res.tagNameForId("pg.title"), "title");
    7.11          assertEquals(res.tagNameForId("pg.button"), "button");
    7.12          assertEquals(res.tagNameForId("pg.text"), "input");
    7.13 +        assertEquals(res.tagNameForId("pg.canvas"), "canvas");
    7.14      }
    7.15      
    7.16      @Test public void testCompileAndRunPageController() throws Exception {
    7.17 @@ -53,11 +54,13 @@
    7.18              + "doc.title.innerHTML = 'nothing';\n"
    7.19              + "doc.text = new Object();\n"
    7.20              + "doc.text.value = 'something';\n"
    7.21 +            + "doc.canvas = new Object();\n"
    7.22              + "doc.getElementById = function(id) {\n"
    7.23              + "    switch(id) {\n"
    7.24              + "      case 'pg.button': return doc.button;\n"
    7.25              + "      case 'pg.title': return doc.title;\n"
    7.26              + "      case 'pg.text': return doc.text;\n"
    7.27 +            + "      case 'pg.canvas': return doc.canvas;\n"
    7.28              + "    }\n"
    7.29              + "    throw id;\n"
    7.30              + "  }\n"
    7.31 @@ -92,11 +95,13 @@
    7.32              + "doc.title.innerHTML = 'nothing';\n"
    7.33              + "doc.text = new Object();\n"
    7.34              + "doc.text.value = 'something';\n"
    7.35 +            + "doc.canvas = new Object();\n"
    7.36              + "doc.getElementById = function(id) {\n"
    7.37              + "    switch(id) {\n"
    7.38              + "      case 'pg.button': return doc.button;\n"
    7.39              + "      case 'pg.title': return doc.title;\n"
    7.40              + "      case 'pg.text': return doc.text;\n"
    7.41 +            + "      case 'pg.canvas': return doc.canvas;\n"
    7.42              + "    }\n"
    7.43              + "    throw id;\n"
    7.44              + "  }\n"
    7.45 @@ -123,6 +128,52 @@
    7.46          assertEquals(ret, "pg.title", "Title has been passed to the method argument");
    7.47      }
    7.48  
    7.49 +    @Test public void clickWithArgumentAndParameterCalled() throws Exception {
    7.50 +        StringBuilder sb = new StringBuilder();
    7.51 +        sb.append(
    7.52 +              "var window = new Object();\n"
    7.53 +            + "var doc = new Object();\n"
    7.54 +            + "var eventObject = new Object();\n"
    7.55 +            + "eventObject.layerX = 100;\n"
    7.56 +            + "doc.button = new Object();\n"
    7.57 +            + "doc.title = new Object();\n"
    7.58 +            + "doc.title.innerHTML = 'nothing';\n"
    7.59 +            + "doc.text = new Object();\n"
    7.60 +            + "doc.text.value = 'something';\n"
    7.61 +            + "doc.canvas = new Object();\n"
    7.62 +            + "doc.canvas.width = 200;\n"                
    7.63 +            + "doc.getElementById = function(id) {\n"
    7.64 +            + "    switch(id) {\n"
    7.65 +            + "      case 'pg.button': return doc.button;\n"
    7.66 +            + "      case 'pg.title': return doc.title;\n"
    7.67 +            + "      case 'pg.text': return doc.text;\n"
    7.68 +            + "      case 'pg.canvas': return doc.canvas;\n"
    7.69 +            + "    }\n"
    7.70 +            + "    throw id;\n"
    7.71 +            + "  }\n"
    7.72 +            + "\n"
    7.73 +            + "function clickAndCheck() {\n"
    7.74 +            + "  doc.canvas.onclick(eventObject);\n"
    7.75 +            + "  return doc.canvas.width.toString();\n"
    7.76 +            + "};\n"
    7.77 +            + "\n"
    7.78 +            + "window.document = doc;\n"
    7.79 +        );
    7.80 +        Invocable i = compileClass(sb, 
    7.81 +            "org/apidesign/bck2brwsr/htmlpage/PageController"
    7.82 +        );
    7.83 +
    7.84 +        Object ret = null;
    7.85 +        try {
    7.86 +            ret = i.invokeFunction("clickAndCheck");
    7.87 +        } catch (ScriptException ex) {
    7.88 +            fail("Execution failed in " + sb, ex);
    7.89 +        } catch (NoSuchMethodException ex) {
    7.90 +            fail("Cannot find method in " + sb, ex);
    7.91 +        }
    7.92 +       assertEquals(ret, "100", "layerX has been passed to the method argument");
    7.93 +    }
    7.94 +    
    7.95      static Invocable compileClass(StringBuilder sb, String... names) throws ScriptException, IOException {
    7.96          if (sb == null) {
    7.97              sb = new StringBuilder();
     8.1 --- a/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html	Tue Mar 05 18:47:29 2013 +0100
     8.2 +++ b/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html	Tue Mar 05 19:00:36 2013 +0100
     8.3 @@ -26,5 +26,6 @@
     8.4      <body>
     8.5          New title: <input id="pg.text"/>
     8.6          <button id="pg.button">Change title!</button>
     8.7 +        <canvas id="pg.canvas" width="100"/>
     8.8      </body>
     8.9  </html>