# HG changeset patch # User Jaroslav Tulach # Date 1372269458 -7200 # Node ID 466c30fd9cb049cb97e5848ee877b956750d59b6 # Parent 592cb4e0f363b200401988d30a8aeb3d1f856ef4 Adding in launcher based support for knockout diff -r 592cb4e0f363 -r 466c30fd9cb0 ko/bck2brwsr/pom.xml --- a/ko/bck2brwsr/pom.xml Wed Jun 26 19:37:34 2013 +0200 +++ b/ko/bck2brwsr/pom.xml Wed Jun 26 19:57:38 2013 +0200 @@ -78,12 +78,12 @@ org.apidesign.html net.java.html.json - 0.4-SNAPSHOT + ${net.java.html.version} org.apidesign.html net.java.html.json.tck - 0.4-SNAPSHOT + ${net.java.html.version} test diff -r 592cb4e0f363 -r 466c30fd9cb0 ko/fx/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko/fx/pom.xml Wed Jun 26 19:57:38 2013 +0200 @@ -0,0 +1,84 @@ + + + 4.0.0 + + org.apidesign.bck2brwsr + ko + 0.8-SNAPSHOT + + org.apidesign.html + ko-fx + 0.8-SNAPSHOT + Knockout.fx in Brwsr + http://maven.apache.org + + ${java.home}/lib/jfxrt.jar + UTF-8 + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + false + + + + + + + com.oracle + javafx + 2.2 + system + ${jfxrt.jar} + + + org.json + json + 20090211 + jar + + + org.apidesign.html + net.java.html.json + ${net.java.html.version} + + + org.testng + testng + test + + + ${project.groupId} + net.java.html.json.tck + ${net.java.html.version} + test + + + org.netbeans.api + org-openide-util + provided + + + org.apidesign.bck2brwsr + launcher.fx + ${project.version} + test + + + org.apidesign.html + net.java.html.boot + ${project.version} + jar + + + org.apidesign.bck2brwsr + vmtest + ${project.version} + test + jar + + + diff -r 592cb4e0f363 -r 466c30fd9cb0 ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/Console.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/Console.java Wed Jun 26 19:57:38 2013 +0200 @@ -0,0 +1,52 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 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. + */ +package org.apidesign.bck2brwsr.kofx; + +import java.util.logging.Logger; +import net.java.html.js.JavaScriptBody; + +/** This is an implementation package - just + * include its JAR on classpath and use official {@link Context} API + * to access the functionality. + *

+ * Redirects JavaScript's messages to Java's {@link Logger}. + * + * @author Jaroslav Tulach + */ +public final class Console { + private static final Logger LOG = Logger.getLogger(Console.class.getName()); + + private Console() { + } + + static void register() { + registerImpl(new Console()); + } + + @JavaScriptBody(args = { "jconsole" }, body = + "console.log = function(m) { jconsole.log(m); };" + + "console.info = function(m) { jconsole.log(m); };" + + "console.error = function(m) { jconsole.log(m); };" + + "console.warn = function(m) { jconsole.log(m); };" + ) + private static native void registerImpl(Console c); + + public void log(String msg) { + LOG.info(msg); + } +} diff -r 592cb4e0f363 -r 466c30fd9cb0 ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/FXContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/FXContext.java Wed Jun 26 19:57:38 2013 +0200 @@ -0,0 +1,106 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 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. + */ +package org.apidesign.bck2brwsr.kofx; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ServiceLoader; +import java.util.logging.Logger; +import netscape.javascript.JSObject; +import org.apidesign.html.context.spi.Contexts; +import org.apidesign.html.json.spi.FunctionBinding; +import org.apidesign.html.json.spi.JSONCall; +import org.apidesign.html.json.spi.PropertyBinding; +import org.apidesign.html.json.spi.Technology; +import org.apidesign.html.json.spi.Transfer; +import org.openide.util.lookup.ServiceProvider; + +/** This is an implementation package - just + * include its JAR on classpath and use official {@link Context} API + * to access the functionality. + *

+ * Registers {@link ContextProvider}, so {@link ServiceLoader} can find it. + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service = Contexts.Provider.class) +public final class FXContext +implements Technology, Transfer, Contexts.Provider { + static final Logger LOG = Logger.getLogger(FXContext.class.getName()); + + @Override + public void fillContext(Contexts.Builder context, Class requestor) { + context.register(Technology.class, this, 100); + context.register(Transfer.class, this, 100); + } + + @Override + public JSObject wrapModel(Object model) { + return (JSObject) Knockout.createBinding(model).koData(); + } + + @Override + public void bind(PropertyBinding b, Object model, JSObject data) { + final boolean isList = false; + final boolean isPrimitive = false; + Knockout.bind(data, model, b, isPrimitive, isList); + } + + @Override + public void valueHasMutated(JSObject data, String propertyName) { + Knockout.valueHasMutated(data, propertyName); + } + + @Override + public void expose(FunctionBinding fb, Object model, JSObject d) { + Knockout.expose(d, fb); + } + + @Override + public void applyBindings(JSObject data) { + Knockout.applyBindings(data); + } + + @Override + public Object wrapArray(Object[] arr) { + return Knockout.toArray(arr); + } + + @Override + public void extract(Object obj, String[] props, Object[] values) { + LoadJSON.extractJSON(obj, props, values); + } + + @Override + public void loadJSON(final JSONCall call) { + LoadJSON.loadJSON(call); + } + + @Override + public M toModel(Class modelClass, Object data) { + if (data instanceof JSObject) { + data = ((JSObject)data).getMember("ko-fx.model"); // NOI18N + } + return modelClass.cast(data); + } + + @Override + public Object toJSON(InputStream is) throws IOException { + return LoadJSON.parse(is); + } +} diff -r 592cb4e0f363 -r 466c30fd9cb0 ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/Knockout.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/Knockout.java Wed Jun 26 19:57:38 2013 +0200 @@ -0,0 +1,196 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 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. + */ +package org.apidesign.bck2brwsr.kofx; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.java.html.js.JavaScriptBody; +import net.java.html.json.Model; +import netscape.javascript.JSObject; +import org.apidesign.html.json.spi.FunctionBinding; +import org.apidesign.html.json.spi.PropertyBinding; + +/** This is an implementation package - just + * include its JAR on classpath and use official {@link Context} API + * to access the functionality. + *

+ * Provides binding between {@link Model models} and knockout.js running + * inside a JavaFX WebView. + * + * @author Jaroslav Tulach + */ +public final class Knockout { + private static final Logger LOG = Logger.getLogger(Knockout.class.getName()); + /** used by tests */ + static Knockout next; + private final Object model; + + Knockout(Object model) { + this.model = model == null ? this : model; + } + + public Object koData() { + return model; + } + + static Object toArray(Object[] arr) { + return InvokeJS.KObject.call("array", arr); + } + + private static int cnt; + public static Knockout createBinding(Object model) { + Object bindings = InvokeJS.create(model, ++cnt); + return new Knockout(bindings); + } + + public void valueHasMutated(String prop) { + valueHasMutated((JSObject) model, prop); + } + public static void valueHasMutated(JSObject model, String prop) { + LOG.log(Level.FINE, "property mutated: {0}", prop); + try { + Object koProp = model.getMember(prop); + if (koProp instanceof JSObject) { + ((JSObject)koProp).call("valueHasMutated"); + } + } catch (Throwable t) { + LOG.log(Level.WARNING, "valueHasMutated failed for " + model + " prop: " + prop, t); + } + } + + static void bind( + Object bindings, Object model, PropertyBinding pb, boolean primitive, boolean array + ) { + final String prop = pb.getPropertyName(); + try { + InvokeJS.bind(bindings, pb, prop, "getValue", pb.isReadOnly() ? null : "setValue", primitive, array); + + ((JSObject)bindings).setMember("ko-fx.model", model); + LOG.log(Level.FINE, "binding defined for {0}: {1}", new Object[]{prop, ((JSObject)bindings).getMember(prop)}); + } catch (Throwable ex) { + LOG.log(Level.WARNING, "binding failed for {0} on {1}", new Object[]{prop, bindings}); + } + } + static void expose(Object bindings, FunctionBinding f) { + final String prop = f.getFunctionName(); + try { + InvokeJS.expose(bindings, f, prop, "call"); + } catch (Throwable ex) { + LOG.log(Level.SEVERE, "Cannot define binding for " + prop + " in model " + f, ex); + } + } + + static void applyBindings(Object bindings) { + InvokeJS.applyBindings(bindings); + } + + private static final class InvokeJS { + static final JSObject KObject; + + static { + final InputStream koScript = Knockout.class.getResourceAsStream("knockout-2.2.1.js"); + assert koScript != null : "Can't load knockout.js"; + BufferedReader r = new BufferedReader(new InputStreamReader(koScript)); + StringBuilder sb = new StringBuilder(); + for (;;) { + try { + String l = r.readLine(); + if (l == null) { + break; + } + sb.append(l).append('\n'); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + exec(sb.toString()); + Object ko = exec("ko"); + assert ko != null : "Knockout library successfully defined 'ko'"; + + Console.register(); + KObject = (JSObject) kObj(); + } + + @JavaScriptBody(args = { "s" }, body = "return eval(s);") + private static native Object exec(String s); + + @JavaScriptBody(args = {}, body = + " var k = {};" + + " k.array= function() {" + + " return Array.prototype.slice.call(arguments);" + + " };" + + " return k;" + ) + private static native Object kObj(); + + @JavaScriptBody(args = { "value", "cnt " }, body = + " var ret = {};" + + " ret.toString = function() { return 'KObject' + cnt + ' value: ' + value + ' props: ' + Object.keys(this); };" + + " return ret;" + ) + static native Object create(Object value, int cnt); + + @JavaScriptBody(args = { "bindings", "model", "prop", "sig" }, body = + " bindings[prop] = function(data, ev) {" + // + " console.log(\" callback on prop: \" + prop);" + + " model[sig](data, ev);" + + " };" + ) + static native Object expose(Object bindings, Object model, String prop, String sig); + + + @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive", "array" }, body = + " var bnd = {" + + " read: function() {" + + " try {" + + " var v = model[getter]();" + // + " console.log(\" getter value \" + v + \" for property \" + prop);" + // + " try { v = v.koData(); } catch (ignore) {" + // + " console.log(\"Cannot convert to koData: \" + ignore);" + // + " };" + // + " console.log(\" getter ret value \" + v);" + // + " for (var pn in v) {" + // + " console.log(\" prop: \" + pn + \" + in + \" + v + \" = \" + v[pn]);" + // + " if (typeof v[pn] == \"function\") console.log(\" its function value:\" + v[pn]());" + // + " }" + // + " console.log(\" all props printed for \" + (typeof v));" + + " return v;" + + " } catch (e) {" + + " alert(\"Cannot call \" + getter + \" on \" + model + \" error: \" + e);" + + " }" + + " }," + + " owner: bindings" + // + " ,deferEvaluation: true" + + " };" + + " if (setter != null) {" + + " bnd.write = function(val) {" + + " model[setter](primitive ? new Number(val) : val);" + + " };" + + " };" + + " bindings[prop] = ko.computed(bnd);" + ) + static native void bind(Object binding, Object model, String prop, String getter, String setter, boolean primitive, boolean array); + + @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);") + private static native void applyBindings(Object bindings); + } +} diff -r 592cb4e0f363 -r 466c30fd9cb0 ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/LoadJSON.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/LoadJSON.java Wed Jun 26 19:57:38 2013 +0200 @@ -0,0 +1,234 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 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. + */ +package org.apidesign.bck2brwsr.kofx; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PushbackInputStream; +import java.io.Reader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Iterator; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; +import javafx.application.Platform; +import net.java.html.js.JavaScriptBody; +import netscape.javascript.JSObject; +import org.apidesign.html.json.spi.JSONCall; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; + +/** This is an implementation package - just + * include its JAR on classpath and use official {@link Context} API + * to access the functionality. + * + * @author Jaroslav Tulach + */ +final class LoadJSON implements Runnable { + private static final Logger LOG = FXContext.LOG; + private static final Executor REQ = Executors.newCachedThreadPool(); + + private final JSONCall call; + private final URL base; + private Throwable error; + private Object json; + + + private LoadJSON(JSONCall call) { + this.call = call; + URL b; + try { + b = new URL(findBaseURL()); + } catch (MalformedURLException ex) { + LOG.log(Level.SEVERE, "Can't find base url for " + call.composeURL("dummy"), ex); + b = null; + } + this.base = b; + } + + public static void loadJSON(JSONCall call) { + REQ.execute(new LoadJSON((call))); + } + + @Override + public void run() { + if (Platform.isFxApplicationThread()) { + if (error != null) { + call.notifyError(error); + } else { + call.notifySuccess(json); + } + return; + } + final String url; + if (call.isJSONP()) { + url = call.composeURL("dummy"); + } else { + url = call.composeURL(null); + } + try { + final URL u = new URL(base, url.replace(" ", "%20")); + URLConnection conn = u.openConnection(); + if (conn instanceof HttpURLConnection) { + HttpURLConnection huc = (HttpURLConnection) conn; + if (call.getMethod() != null) { + huc.setRequestMethod(call.getMethod()); + } + if (call.isDoOutput()) { + huc.setDoOutput(true); + final OutputStream os = huc.getOutputStream(); + call.writeData(os); + os.flush(); + } + } + final PushbackInputStream is = new PushbackInputStream( + conn.getInputStream(), 1 + ); + boolean array = false; + boolean string = false; + if (call.isJSONP()) { + for (;;) { + int ch = is.read(); + if (ch == -1) { + break; + } + if (ch == '[') { + is.unread(ch); + array = true; + break; + } + if (ch == '{') { + is.unread(ch); + break; + } + } + } else { + int ch = is.read(); + if (ch == -1) { + string = true; + } else { + array = ch == '['; + is.unread(ch); + if (!array && ch != '{') { + string = true; + } + } + } + try { + if (string) { + throw new JSONException(""); + } + Reader r = new InputStreamReader(is, "UTF-8"); + + JSONTokener tok = new JSONTokener(r); + Object obj; + obj = array ? new JSONArray(tok) : new JSONObject(tok); + json = convertToArray(obj); + } catch (JSONException ex) { + Reader r = new InputStreamReader(is, "UTF-8"); + StringBuilder sb = new StringBuilder(); + for (;;) { + int ch = r.read(); + if (ch == -1) { + break; + } + sb.append((char)ch); + } + json = sb.toString(); + } + } catch (IOException ex) { + error = ex; + LOG.log(Level.WARNING, "Cannot connect to " + url, ex); + } finally { + Platform.runLater(this); + } + } + + private static Object convertToArray(Object o) throws JSONException { + if (o instanceof JSONArray) { + JSONArray ja = (JSONArray)o; + Object[] arr = new Object[ja.length()]; + for (int i = 0; i < arr.length; i++) { + arr[i] = convertToArray(ja.get(i)); + } + return arr; + } else if (o instanceof JSONObject) { + JSONObject obj = (JSONObject)o; + Iterator it = obj.keys(); + while (it.hasNext()) { + String key = (String)it.next(); + obj.put(key, convertToArray(obj.get(key))); + } + return obj; + } else { + return o; + } + } + + public static void extractJSON(Object jsonObject, String[] props, Object[] values) { + if (jsonObject instanceof JSONObject) { + JSONObject obj = (JSONObject)jsonObject; + for (int i = 0; i < props.length; i++) { + try { + values[i] = obj.has(props[i]) ? obj.get(props[i]) : null; + } catch (JSONException ex) { + LoadJSON.LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex); + } + } + } + if (jsonObject instanceof JSObject) { + JSObject obj = (JSObject)jsonObject; + for (int i = 0; i < props.length; i++) { + Object val = obj.getMember(props[i]); + values[i] = isDefined(val) ? val : null; + } + } + } + + public static Object parse(InputStream is) throws IOException { + try { + InputStreamReader r = new InputStreamReader(is, "UTF-8"); + JSONTokener t = new JSONTokener(r); + return new JSONObject(t); + } catch (JSONException ex) { + throw new IOException(ex); + } + } + + @JavaScriptBody(args = { }, body = + "var h;" + + "if (!!window && !!window.location && !!window.location.href)\n" + + " h = window.location.href;\n" + + "else " + + " h = null;" + + "return h;\n" + ) + private static native String findBaseURL(); + + private static boolean isDefined(Object val) { + return !"undefined".equals(val); + } +} diff -r 592cb4e0f363 -r 466c30fd9cb0 ko/fx/src/main/resources/org/apidesign/html/kofx/knockout-2.2.1.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko/fx/src/main/resources/org/apidesign/html/kofx/knockout-2.2.1.js Wed Jun 26 19:57:38 2013 +0200 @@ -0,0 +1,3594 @@ +// Knockout JavaScript library v2.2.1 +// (c) Steven Sanderson - http://knockoutjs.com/ +// License: MIT (http://www.opensource.org/licenses/mit-license.php) + +(function(){ +var DEBUG=true; +(function(window,document,navigator,jQuery,undefined){ +!function(factory) { + // Support three module loading scenarios + if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { + // [1] CommonJS/Node.js + var target = module['exports'] || exports; // module.exports is for Node.js + factory(target); + } else if (typeof define === 'function' && define['amd']) { + // [2] AMD anonymous module + define(['exports'], factory); + } else { + // [3] No module loader (plain "); + }; + + if (jQueryTmplVersion > 0) { + jQuery['tmpl']['tag']['ko_code'] = { + open: "__.push($1 || '');" + }; + jQuery['tmpl']['tag']['ko_with'] = { + open: "with($1) {", + close: "} " + }; + } + }; + + ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine(); + + // Use this one by default *only if jquery.tmpl is referenced* + var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine(); + if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0) + ko.setTemplateEngine(jqueryTmplTemplateEngineInstance); + + ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine); +})(); +}); +})(window,document,navigator,window["jQuery"]); +})(); \ No newline at end of file diff -r 592cb4e0f363 -r 466c30fd9cb0 ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/KnockoutFXTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/KnockoutFXTest.java Wed Jun 26 19:57:38 2013 +0200 @@ -0,0 +1,123 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 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. + */ +package org.apidesign.bck2brwsr.kofx; + +import org.apidesign.bck2brwsr.kofx.FXContext; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Map; +import net.java.html.BrwsrCtx; +import net.java.html.js.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.apidesign.html.context.spi.Contexts; +import org.apidesign.html.json.spi.Technology; +import org.apidesign.html.json.spi.Transfer; +import org.apidesign.html.json.tck.KOTest; +import org.apidesign.html.json.tck.KnockoutTCK; +import org.json.JSONException; +import org.json.JSONObject; +import org.openide.util.lookup.ServiceProvider; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service = KnockoutTCK.class) +public final class KnockoutFXTest extends KnockoutTCK { + public KnockoutFXTest() { + } + + @Factory public static Object[] compatibilityTests() { + return VMTest.newTests(). + withClasses(testClasses()). + withTestAnnotation(KOTest.class). + withLaunchers("fxbrwsr").build(); + } + + @Override + public BrwsrCtx createContext() { + FXContext fx = new FXContext(); + return Contexts.newBuilder(). + register(Technology.class, fx, 10). + register(Transfer.class, fx, 10). + build(); + } + + @Override + public Object createJSON(Map values) { + JSONObject json = new JSONObject(); + for (Map.Entry entry : values.entrySet()) { + try { + json.put(entry.getKey(), entry.getValue()); + } catch (JSONException ex) { + throw new IllegalStateException(ex); + } + } + return json; + } + + @Override + @JavaScriptBody(args = { "s", "args" }, body = "" + + "var f = new Function(s); " + + "return f.apply(null, args);" + ) + public native Object executeScript(String script, Object[] arguments); + + @JavaScriptBody(args = { }, body = + "var h;" + + "if (!!window && !!window.location && !!window.location.href)\n" + + " h = window.location.href;\n" + + "else " + + " h = null;" + + "return h;\n" + ) + private static native String findBaseURL(); + + @Override + public URI prepareURL(String content, String mimeType, String[] parameters) { + try { + final URL baseURL = new URL(findBaseURL()); + StringBuilder sb = new StringBuilder(); + sb.append("/dynamic?mimeType=").append(mimeType); + for (int i = 0; i < parameters.length; i++) { + sb.append("¶m" + i).append("=").append(parameters[i]); + } + String mangle = content.replace("\n", "%0a") + .replace("\"", "\\\"").replace(" ", "%20"); + sb.append("&content=").append(mangle); + + URL query = new URL(baseURL, sb.toString()); + URLConnection c = query.openConnection(); + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); + URI connectTo = new URI(br.readLine()); + return connectTo; + } catch (IOException ex) { + throw new IllegalStateException(ex); + } catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } +} diff -r 592cb4e0f363 -r 466c30fd9cb0 ko/pom.xml --- a/ko/pom.xml Wed Jun 26 19:37:34 2013 +0200 +++ b/ko/pom.xml Wed Jun 26 19:57:38 2013 +0200 @@ -11,9 +11,13 @@ bck2brwsr 0.8-SNAPSHOT + + 0.4-SNAPSHOT + archetype archetype-test bck2brwsr + fx diff -r 592cb4e0f363 -r 466c30fd9cb0 pom.xml --- a/pom.xml Wed Jun 26 19:37:34 2013 +0200 +++ b/pom.xml Wed Jun 26 19:57:38 2013 +0200 @@ -92,7 +92,7 @@ dew/src/main/resources/org/apidesign/bck2brwsr/dew/** javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout*.js ko/archetype/src/main/resources/archetype-resources/** - ko/bck2brwsr/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js + ko/*/src/main/resources/org/apidesign/*/*/knockout-2.2.1.js