# HG changeset patch # User Jaroslav Tulach # Date 1372271226 -7200 # Node ID 43fba26ba0c05d519817b5d9081811887516a8a8 # Parent 17ca7fe5c486519916d2a006fe42441ffe10818c Using the net.java.html's ko-fx implementation diff -r 17ca7fe5c486 -r 43fba26ba0c0 ko/fx/pom.xml --- a/ko/fx/pom.xml Wed Jun 26 20:11:13 2013 +0200 +++ b/ko/fx/pom.xml Wed Jun 26 20:27:06 2013 +0200 @@ -74,6 +74,12 @@ jar + org.apidesign.html + ko-fx + ${net.java.html.version} + jar + + org.apidesign.bck2brwsr vmtest ${project.version} diff -r 17ca7fe5c486 -r 43fba26ba0c0 ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/Console.java --- a/ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/Console.java Wed Jun 26 20:11:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/** - * 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 17ca7fe5c486 -r 43fba26ba0c0 ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/FXContext.java --- a/ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/FXContext.java Wed Jun 26 20:11:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/** - * 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 17ca7fe5c486 -r 43fba26ba0c0 ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/Knockout.java --- a/ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/Knockout.java Wed Jun 26 20:11:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -/** - * 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 17ca7fe5c486 -r 43fba26ba0c0 ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/LoadJSON.java --- a/ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/LoadJSON.java Wed Jun 26 20:11:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,234 +0,0 @@ -/** - * 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 17ca7fe5c486 -r 43fba26ba0c0 ko/fx/src/main/resources/org/apidesign/bck2brwsr/kofx/knockout-2.2.1.js --- a/ko/fx/src/main/resources/org/apidesign/bck2brwsr/kofx/knockout-2.2.1.js Wed Jun 26 20:11:13 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3594 +0,0 @@ -// 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 17ca7fe5c486 -r 43fba26ba0c0 ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/KnockoutFXTest.java --- a/ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/KnockoutFXTest.java Wed Jun 26 20:11:13 2013 +0200 +++ b/ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/KnockoutFXTest.java Wed Jun 26 20:27:06 2013 +0200 @@ -17,12 +17,9 @@ */ 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; @@ -36,6 +33,7 @@ import org.apidesign.html.json.spi.Transfer; import org.apidesign.html.json.tck.KOTest; import org.apidesign.html.json.tck.KnockoutTCK; +import org.apidesign.html.kofx.FXContext; import org.json.JSONException; import org.json.JSONObject; import org.openide.util.lookup.ServiceProvider; diff -r 17ca7fe5c486 -r 43fba26ba0c0 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Wed Jun 26 20:11:13 2013 +0200 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Wed Jun 26 20:27:06 2013 +0200 @@ -17,6 +17,7 @@ */ package org.apidesign.bck2brwsr.launcher.fximpl; +import java.io.BufferedReader; import java.io.Reader; import org.apidesign.html.boot.spi.Fn; import java.net.URL; @@ -103,12 +104,21 @@ @Override public void displayPage(URL page, Runnable onPageLoad) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public void loadScript(Reader code) throws Exception { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + BufferedReader r = new BufferedReader(code); + StringBuilder sb = new StringBuilder(); + for (;;) { + String l = r.readLine(); + if (l == null) { + break; + } + sb.append(l).append('\n'); + } + engine.executeScript(sb.toString()); } }