# HG changeset patch # User Jaroslav Tulach # Date 1349961322 25200 # Node ID 029e6eed60e91b10b133a921f30cda5cec704348 # Parent 67e892757752031ed39b86e54f62df3718fbc6d1 Now we are able to change a title of a page inside of a browser diff -r 67e892757752 -r 029e6eed60e9 htmlpage/pom.xml --- a/htmlpage/pom.xml Thu Oct 11 04:11:42 2012 -0700 +++ b/htmlpage/pom.xml Thu Oct 11 06:15:22 2012 -0700 @@ -31,6 +31,25 @@ org.netbeans.api org-openide-util-lookup + + org.apidesign.bck2brwsr + core + 1.0-SNAPSHOT + jar + + + org.apidesign.bck2brwsr + emul + 1.0-SNAPSHOT + jar + + + org.apidesign.bck2brwsr + vm4brwsr + 0.1-SNAPSHOT + jar + test + diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java --- a/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Thu Oct 11 04:11:42 2012 -0700 +++ b/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Thu Oct 11 06:15:22 2012 -0700 @@ -55,7 +55,7 @@ public boolean process(Set annotations, RoundEnvironment roundEnv) { for (Element e : roundEnv.getElementsAnnotatedWith(Page.class)) { Page p = e.getAnnotation(Page.class); - PackageElement pe = (PackageElement)e; + PackageElement pe = (PackageElement)e.getEnclosingElement(); String pkg = pe.getQualifiedName().toString(); ProcessPage pp; diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java --- a/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Thu Oct 11 04:11:42 2012 -0700 +++ b/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Thu Oct 11 06:15:22 2012 -0700 @@ -17,6 +17,8 @@ */ package org.apidesign.bck2brwsr.htmlpage.api; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + /** Represents a generic HTML element. * * @author Jaroslav Tulach @@ -30,14 +32,33 @@ abstract void dontSubclass(); + @JavaScriptBody( + args={"el", "property", "value"}, + body="var e = window.document.getElementById(el.id);\n" + + "e[property] = value;\n" + ) static void setAttribute(Element el, String property, Object value) { throw new UnsupportedOperationException("Needs JavaScript!"); } + + @JavaScriptBody( + args={"el", "property"}, + body="var e = window.document.getElementById(el.id);\n" + + "return e[property];\n" + ) + static Object getAttribute(Element el, String property) { + throw new UnsupportedOperationException("Needs JavaScript!"); + } /** Executes given runnable when user performs a "click" on the given * element. * @param r the runnable to execute, never null */ + @JavaScriptBody( + args={"el", "r"}, + body="var e = window.document.getElementById(el.id);\n" + + "e.onclick = function() { r.runV(); };\n" + ) public final void addOnClick(Runnable r) { throw new UnsupportedOperationException("Needs JavaScript!"); } diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.js --- a/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.js Thu Oct 11 04:11:42 2012 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ - - -function org_apidesign_bck2brwsr_htmlpage_api_Element_setAttribute_Lorg_apidesign_bck2brwsr_htmlpage_api_ElementLjava_lang_StringLjava_lang_Object(self, property, value) { - document.getElementById(self.id)[property] = value; -} - -function org_apidesign_bck2brwsr_htmlpage_api_Element_addOnClick_Ljava_lang_Runnable(self, run) { - document.getElementById(self.id).onClick = function() { run.runV(); }; -} - diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Input.java --- a/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Input.java Thu Oct 11 04:11:42 2012 -0700 +++ b/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Input.java Thu Oct 11 06:15:22 2012 -0700 @@ -31,6 +31,10 @@ } public void setAutocomplete(boolean state) { - setAttribute(this, "autocomplete", state); + Element.setAttribute(this, "autocomplete", state); + } + + public final String getValue() { + return (String)Element.getAttribute(this, "value"); } } diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Page.java --- a/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Page.java Thu Oct 11 04:11:42 2012 -0700 +++ b/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Page.java Thu Oct 11 06:15:22 2012 -0700 @@ -32,7 +32,7 @@ * @author Jaroslav Tulach */ @Retention(RetentionPolicy.SOURCE) -@Target(ElementType.PACKAGE) +@Target(ElementType.TYPE) public @interface Page { /** Path to the XHTML page to read in */ String xhtml(); diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Title.java --- a/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Title.java Thu Oct 11 04:11:42 2012 -0700 +++ b/htmlpage/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Title.java Thu Oct 11 06:15:22 2012 -0700 @@ -29,4 +29,8 @@ @Override void dontSubclass() { } + + public final void setText(String text) { + Element.setAttribute(this, "innerHTML", text); + } } diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/htmlpage/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Thu Oct 11 06:15:22 2012 -0700 @@ -0,0 +1,32 @@ +package org.apidesign.bck2brwsr.htmlpage; + +import org.apidesign.bck2brwsr.htmlpage.api.OnClick; +import org.apidesign.bck2brwsr.htmlpage.api.Page; + +/** Trivial demo for the bck2brwsr project. First of all start + * with your XHTML page. Include there + * a script that will boot Java in your browser. + *

+ * Then use @Page annotation to + * generate a Java representation of elements with IDs in that page. + * Depending on the type of the elements, they will have different + * methods (e.g. PG_TITLE has setText, etc.). + * Use @OnClick annotation to associate behavior + * with existing elements. Use the generated elements + * (PG_TITLE, PG_TEXT) to modify the page. + *

+ * Everything is type-safe. As soon as somebody modifies the page and + * removes the IDs or re-assigns them to wrong elements. Java compiler + * will emit an error. + *

+ * Welcome to the type-safe HTML5 world! + * + * @author Jaroslav Tulach + */ +@Page(xhtml="TestPage.html", name="TestPage") +public class PageController { + @OnClick(id="pg.button") + static void updateTitle() { + TestPage.PG_TITLE.setText(TestPage.PG_TEXT.getValue()); + } +} diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java --- a/htmlpage/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Thu Oct 11 04:11:42 2012 -0700 +++ b/htmlpage/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Thu Oct 11 06:15:22 2012 -0700 @@ -19,17 +19,20 @@ import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Method; import java.util.Set; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; import org.testng.annotations.Test; import static org.testng.Assert.*; -import org.apidesign.bck2brwsr.htmlpage.api.*; - public class ProcessPageTest { @Test public void findsThreeIds() throws IOException { - InputStream is = ProcessPageTest.class.getResourceAsStream("TestPage.xhtml"); + InputStream is = ProcessPageTest.class.getResourceAsStream("TestPage.html"); assertNotNull(is, "Sample HTML page found"); ProcessPage res = ProcessPage.readPage(is); final Set ids = res.ids(); @@ -40,16 +43,67 @@ assertEquals(res.tagNameForId("pg.text"), "input"); } - void testWhetherWeCanCallTheGeneratedIdFields() { - Title t = TestPage.PG_TITLE; + @Test public void testCompileAndRunPageController() throws Exception { + StringBuilder sb = new StringBuilder(); + sb.append( + "var window = new Object();\n" + + "var doc = new Object();\n" + + "doc.button = new Object();\n" + + "doc.title = new Object();\n" + + "doc.title.innerHTML = 'nothing';\n" + + "doc.text = new Object();\n" + + "doc.text.value = 'something';\n" + + "doc.getElementById = function(id) {\n" + + " switch(id) {\n" + + " case 'pg.button': return doc.button;\n" + + " case 'pg.title': return doc.title;\n" + + " case 'pg.text': return doc.text;\n" + + " }\n" + + " throw id;\n" + + " }\n" + + "\n" + + "function clickAndCheck() {\n" + + " doc.button.onclick();\n" + + " return doc.title.innerHTML.toString();\n" + + "};\n" + + "\n" + + "window.document = doc;\n" + ); + Invocable i = compileClass(sb, "org/apidesign/bck2brwsr/htmlpage/PageController"); + + Object ret = null; + try { + ret = i.invokeFunction("clickAndCheck"); + } catch (ScriptException ex) { + fail("Execution failed in " + sb, ex); + } catch (NoSuchMethodException ex) { + fail("Cannot find method in " + sb, ex); + } + assertEquals(ret, "something", "We expect that the JavaCode performs all the wiring"); } - - @OnClick(id="pg.button") - static void handleButtonClick() { - - } - - @Test public void testOnclickHandlerGenerated() { - + + static Invocable compileClass(StringBuilder sb, String... names) throws ScriptException, IOException { + if (sb == null) { + sb = new StringBuilder(); + } + try { + Method m; + Class genJS = Class.forName("org.apidesign.vm4brwsr.GenJS"); + m = genJS.getDeclaredMethod("compile", Appendable.class, String[].class); + m.setAccessible(true); + m.invoke(null, sb, names); + } catch (Exception exception) { + throw new IOException(exception); + } + ScriptEngineManager sem = new ScriptEngineManager(); + ScriptEngine js = sem.getEngineByExtension("js"); + try { + Object res = js.eval(sb.toString()); + assertTrue(js instanceof Invocable, "It is invocable object: " + res); + return (Invocable) js; + } catch (ScriptException ex) { + fail("Could not compile:\n" + sb, ex); + return null; + } } } diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/test/java/org/apidesign/bck2brwsr/htmlpage/package-info.java --- a/htmlpage/src/test/java/org/apidesign/bck2brwsr/htmlpage/package-info.java Thu Oct 11 04:11:42 2012 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -/** - * Java 4 Browser Bytecode Translator - * Copyright (C) 2012-2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -@Page(xhtml="TestPage.xhtml", name="TestPage") -package org.apidesign.bck2brwsr.htmlpage; - -import org.apidesign.bck2brwsr.htmlpage.api.Page; - diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/htmlpage/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.html Thu Oct 11 06:15:22 2012 -0700 @@ -0,0 +1,30 @@ + + + + + + Default Title + + + New title: + + + diff -r 67e892757752 -r 029e6eed60e9 htmlpage/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.xhtml --- a/htmlpage/src/test/resources/org/apidesign/bck2brwsr/htmlpage/TestPage.xhtml Thu Oct 11 04:11:42 2012 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ - - - - - - Default Title - - - New title: - - - diff -r 67e892757752 -r 029e6eed60e9 vm/pom.xml --- a/vm/pom.xml Thu Oct 11 04:11:42 2012 -0700 +++ b/vm/pom.xml Thu Oct 11 06:15:22 2012 -0700 @@ -7,7 +7,7 @@ 1.0-SNAPSHOT - org.apidesign + org.apidesign.bck2brwsr vm4brwsr 0.1-SNAPSHOT jar