1.1 --- a/boot-script/src/main/java/net/java/html/boot/script/Scripts.java Sun Jul 13 23:49:46 2014 +0200
1.2 +++ b/boot-script/src/main/java/net/java/html/boot/script/Scripts.java Sun Jul 13 23:50:25 2014 +0200
1.3 @@ -42,10 +42,12 @@
1.4 */
1.5 package net.java.html.boot.script;
1.6
1.7 +import java.io.Closeable;
1.8 import java.util.concurrent.Executor;
1.9 import javax.script.ScriptEngine;
1.10 import net.java.html.boot.BrowserBuilder;
1.11 import net.java.html.js.JavaScriptBody;
1.12 +import org.apidesign.html.boot.spi.Fn;
1.13 import org.apidesign.html.boot.spi.Fn.Presenter;
1.14
1.15 /** Implementations of {@link Presenter}s that delegate
1.16 @@ -55,14 +57,29 @@
1.17 * <pre>
1.18 *
1.19 * {@link Runnable} <em>run</em> = ...; // your own init code
1.20 - * {@link Presenter Fn.Presenter} <em>p</em> = Scripts.{@link Scripts#createPresenter()};
1.21 - * BrowserBuilder.{@link BrowserBuilder#newBrowser(java.lang.Object...) newBrowser(<em>p</em>)}.
1.22 + * {@link Presenter Fn.Presenter} <b>p</b> = Scripts.{@link Scripts#createPresenter()};
1.23 + * BrowserBuilder.{@link BrowserBuilder#newBrowser(java.lang.Object...) newBrowser(<b>p</b>)}.
1.24 * {@link BrowserBuilder#loadFinished(java.lang.Runnable) loadFinished(run)}.
1.25 * {@link BrowserBuilder#showAndWait()};
1.26 * </pre>
1.27 *
1.28 * and your runnable can make extensive use of {@link JavaScriptBody} directly or
1.29 * indirectly via APIs using {@link JavaScriptBody such annotation} themselves.
1.30 + * <p>
1.31 + * Alternatively one can manipulate the presenter manually, which is
1.32 + * especially useful when writing tests:
1.33 + * <pre>
1.34 + * {@code @Test} public void runInASimulatedBrowser() throws Exception {
1.35 + * {@link Presenter Fn.Presenter} <b>p</b> = Scripts.{@link Scripts#createPresenter()};
1.36 + * try ({@link Closeable} c = {@link Fn#activate(org.apidesign.html.boot.spi.Fn.Presenter) Fn.activate}(<b>p</b>)) {
1.37 + * // your code operating in context of <b>p</b>
1.38 + * }
1.39 + * }
1.40 + * </pre>
1.41 + * The previous code snippet requires Java 7 language syntax, as it relies
1.42 + * on try-with-resources language syntactic sugar feature. The same block
1.43 + * of code can be used on older versions of Java, but it is slightly more
1.44 + * verbose.
1.45 *
1.46 * @author Jaroslav Tulach
1.47 */
2.1 --- a/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java Sun Jul 13 23:49:46 2014 +0200
2.2 +++ b/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java Sun Jul 13 23:50:25 2014 +0200
2.3 @@ -193,8 +193,9 @@
2.4 return FnContext.currentPresenter(false);
2.5 }
2.6
2.7 - /** Activates given presenter. Used by the code generated by
2.8 - * {@link JavaScriptBody} annotation:
2.9 + /** Activates given presenter. Used to associate the native
2.10 + * JavaScript code specified by
2.11 + * {@link JavaScriptBody} annotation with certain presenter:
2.12 * <pre>
2.13 * try ({@link Closeable} c = Fn.activate(presenter)) {
2.14 * doCallsInPresenterContext();
3.1 --- a/geo/src/main/java/net/java/html/geo/OnLocation.java Sun Jul 13 23:49:46 2014 +0200
3.2 +++ b/geo/src/main/java/net/java/html/geo/OnLocation.java Sun Jul 13 23:50:25 2014 +0200
3.3 @@ -64,7 +64,7 @@
3.4 * In case something goes wrong a method in the same class named {@link #onError()}
3.5 * can be specified (should take one {@link Exception} parameter).
3.6 * <p>
3.7 - * The overall behavior of the system mimics <a href="http://www.w3.org/TR/2012/PRgeolocationAPI20120510/">
3.8 + * The overall behavior of the system mimics <a href="http://www.w3.org/TR/geolocation-API/">
3.9 * W3C's Geolocation API</a>.
3.10 *
3.11 * @author Jaroslav Tulach <jtulach@netbeans.org>
4.1 --- a/geo/src/main/java/net/java/html/geo/Position.java Sun Jul 13 23:49:46 2014 +0200
4.2 +++ b/geo/src/main/java/net/java/html/geo/Position.java Sun Jul 13 23:50:25 2014 +0200
4.3 @@ -90,24 +90,46 @@
4.4 this.data = data;
4.5 }
4.6
4.7 + /**
4.8 + * @return geographic coordinate specified in decimal degrees.
4.9 + */
4.10 public double getLatitude() {
4.11 return ((Number)JsG.get(data, "latitude")).doubleValue(); // NOI18N
4.12 }
4.13
4.14 + /**
4.15 + * @return geographic coordinate specified in decimal degrees.
4.16 + */
4.17 public double getLongitude() {
4.18 return ((Number)JsG.get(data, "longitude")).doubleValue(); // NOI18N
4.19 - }
4.20 + }
4.21
4.22 + /**
4.23 + * The accuracy attribute denotes the accuracy level of the latitude
4.24 + * and longitude coordinates. It is specified in meters.
4.25 + * The value of the accuracy attribute must be a non-negative number.
4.26 + *
4.27 + * @return accuracy in meters
4.28 + */
4.29 public double getAccuracy() {
4.30 return ((Number)JsG.get(data, "accuracy")).doubleValue(); // NOI18N
4.31 }
4.32
4.33 - /** @return may return null, if the information is not available */
4.34 + /** Denotes the height of the position, specified in meters above the ellipsoid.
4.35 + * If the implementation cannot provide altitude information,
4.36 + * the value of this attribute must be null.
4.37 + * @return value in meters, may return null, if the information is not available
4.38 + */
4.39 public Double getAltitude() {
4.40 return (Double)JsG.get(data, "altitude"); // NOI18N
4.41 }
4.42
4.43 - /** @return may return null, if the information is not available */
4.44 + /** The altitude accuracy is specified in meters.
4.45 + * If the implementation cannot provide altitude information,
4.46 + * the value of this attribute must be null. Otherwise, the value
4.47 + * must be a non-negative real number.
4.48 + * @return value in meters; may return null, if the information is not available
4.49 + */
4.50 public Double getAltitudeAccuracy() {
4.51 return (Double)JsG.get(data, "altitudeAccuracy"); // NOI18N
4.52 }
5.1 --- a/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java Sun Jul 13 23:49:46 2014 +0200
5.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java Sun Jul 13 23:50:25 2014 +0200
5.3 @@ -43,6 +43,8 @@
5.4 package net.java.html.json.tests;
5.5
5.6 import java.util.List;
5.7 +import java.util.Timer;
5.8 +import java.util.TimerTask;
5.9 import net.java.html.BrwsrCtx;
5.10 import net.java.html.json.ComputedProperty;
5.11 import net.java.html.json.Function;
5.12 @@ -64,6 +66,7 @@
5.13 @Property(name="latitude", type=double.class)
5.14 })
5.15 public final class KnockoutTest {
5.16 + private KnockoutModel js;
5.17
5.18 @KOTest public void modifyValueAssertChangeInModelOnDouble() throws Throwable {
5.19 Object exp = Utils.exposeHTML(KnockoutTest.class,
5.20 @@ -137,6 +140,38 @@
5.21 }
5.22 }
5.23
5.24 + @KOTest public void modifyValueAssertAsyncChangeInModel() throws Exception {
5.25 + if (js == null) {
5.26 + Utils.exposeHTML(KnockoutTest.class,
5.27 + "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
5.28 + "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
5.29 + "<button id=\"hello\">Say Hello!</button>\n"
5.30 + );
5.31 +
5.32 + js = Models.bind(new KnockoutModel(), newContext());
5.33 + js.setName("Kukuc");
5.34 + js.applyBindings();
5.35 +
5.36 + String v = getSetInput(null);
5.37 + assert "Kukuc".equals(v) : "Value is really kukuc: " + v;
5.38 +
5.39 + Timer t = new Timer("Set to Jardo");
5.40 + t.schedule(new TimerTask() {
5.41 + @Override
5.42 + public void run() {
5.43 + js.setName("Jardo");
5.44 + }
5.45 + }, 1);
5.46 + }
5.47 +
5.48 + String v = getSetInput(null);
5.49 + if (!"Jardo".equals(v)) {
5.50 + throw new InterruptedException();
5.51 + }
5.52 +
5.53 + Utils.exposeHTML(KnockoutTest.class, "");
5.54 + }
5.55 +
5.56 private static String getSetInput(String value) throws Exception {
5.57 String s = "var value = arguments[0];\n"
5.58 + "var n = window.document.getElementById('input'); \n "
5.59 @@ -185,6 +220,45 @@
5.60 }
5.61 }
5.62
5.63 + @KOTest public void displayContentOfAsyncArray() throws Exception {
5.64 + if (js == null) {
5.65 + Utils.exposeHTML(KnockoutTest.class,
5.66 + "<ul id='ul' data-bind='foreach: results'>\n"
5.67 + + " <li data-bind='text: $data, click: $root.call'/>\n"
5.68 + + "</ul>\n"
5.69 + );
5.70 + js = Models.bind(new KnockoutModel(), newContext());
5.71 + js.getResults().add("Ahoj");
5.72 + js.applyBindings();
5.73 +
5.74 + int cnt = Utils.countChildren(KnockoutTest.class, "ul");
5.75 + assert cnt == 1 : "One child, but was " + cnt;
5.76 +
5.77 + Timer t = new Timer("add to array");
5.78 + t.schedule(new TimerTask() {
5.79 + @Override
5.80 + public void run() {
5.81 + js.getResults().add("Hi");
5.82 + }
5.83 + }, 1);
5.84 + }
5.85 +
5.86 +
5.87 + int cnt = Utils.countChildren(KnockoutTest.class, "ul");
5.88 + if (cnt != 2) {
5.89 + throw new InterruptedException();
5.90 + }
5.91 +
5.92 + try {
5.93 + triggerChildClick("ul", 1);
5.94 +
5.95 + assert 1 == js.getCallbackCount() : "One callback " + js.getCallbackCount();
5.96 + assert "Hi".equals(js.getName()) : "We got callback from 2nd child " + js.getName();
5.97 + } finally {
5.98 + Utils.exposeHTML(KnockoutTest.class, "");
5.99 + }
5.100 + }
5.101 +
5.102 @KOTest public void displayContentOfComputedArray() throws Exception {
5.103 Object exp = Utils.exposeHTML(KnockoutTest.class,
5.104 "<ul id='ul' data-bind='foreach: bothNames'>\n"
6.1 --- a/json-tck/src/main/java/net/java/html/json/tests/OperationsTest.java Sun Jul 13 23:49:46 2014 +0200
6.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/OperationsTest.java Sun Jul 13 23:50:25 2014 +0200
6.3 @@ -66,19 +66,7 @@
6.4
6.5 @KOTest public void asyncOperation() throws InterruptedException {
6.6 if (js == null) {
6.7 - try {
6.8 - // needs full JVM (not Bck2Brwsr VM) to run
6.9 - Class<?> thread = Class.forName("java.lang.Thread");
6.10 - Thread t = new Thread("Empty");
6.11 - // following operations are supposed to generate SecurityException
6.12 - // on bck2brwsr VM
6.13 - t.setName("Different");
6.14 - t.setDaemon(false);
6.15 - t.interrupt();
6.16 - t.start();
6.17 - } catch (ClassNotFoundException ex) {
6.18 - return;
6.19 - } catch (SecurityException ex) {
6.20 + if (Utils.skipIfNoFullJDK()) {
6.21 return;
6.22 }
6.23
6.24 @@ -104,7 +92,4 @@
6.25 assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
6.26 assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
6.27 }
6.28 -
6.29 -
6.30 -
6.31 }
7.1 --- a/json-tck/src/main/java/net/java/html/json/tests/Utils.java Sun Jul 13 23:49:46 2014 +0200
7.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/Utils.java Sun Jul 13 23:50:25 2014 +0200
7.3 @@ -56,6 +56,22 @@
7.4 public final class Utils {
7.5 private static KnockoutTCK instantiatedTCK;
7.6
7.7 + static boolean skipIfNoFullJDK() {
7.8 + try {
7.9 + Class<?> thread = Class.forName("java.lang.Thread");
7.10 + Thread t = new Thread("Empty");
7.11 + t.setName("Different");
7.12 + t.setDaemon(false);
7.13 + t.interrupt();
7.14 + t.start();
7.15 + } catch (ClassNotFoundException ex) {
7.16 + return true;
7.17 + } catch (SecurityException ex) {
7.18 + return true;
7.19 + }
7.20 + return false;
7.21 + }
7.22 +
7.23 private Utils() {
7.24 }
7.25
8.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Proto.java Sun Jul 13 23:49:46 2014 +0200
8.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Proto.java Sun Jul 13 23:50:25 2014 +0200
8.3 @@ -110,14 +110,22 @@
8.4 }
8.5
8.6 /** Whenever model changes a property. It should notify the
8.7 - * associated technology by calling this method.
8.8 + * associated technology by calling this method.
8.9 + * Since 0.8.3: This method may be called by any thread - it reschedules
8.10 + * its actual execution into appropriate one by using
8.11 + * {@link BrwsrCtx#execute(java.lang.Runnable)}.
8.12 *
8.13 * @param propName name of the changed property
8.14 */
8.15 - public void valueHasMutated(String propName) {
8.16 - if (ko != null) {
8.17 - ko.valueHasMutated(propName, null, null);
8.18 - }
8.19 + public void valueHasMutated(final String propName) {
8.20 + context.execute(new Runnable() {
8.21 + @Override
8.22 + public void run() {
8.23 + if (ko != null) {
8.24 + ko.valueHasMutated(propName, null, null);
8.25 + }
8.26 + }
8.27 + });
8.28 }
8.29
8.30 /** Whenever model changes a propertyit should notify the
8.31 @@ -125,16 +133,26 @@
8.32 * (if the new value is known and different to the old one) or
8.33 * via (slightly ineffective) {@link #valueHasMutated(java.lang.String)}
8.34 * method.
8.35 + * Since 0.8.3: This method may be called by any thread - it reschedules
8.36 + * its actual execution into appropriate one by using
8.37 + * {@link BrwsrCtx#execute(java.lang.Runnable)}.
8.38 *
8.39 * @param propName name of the changed property
8.40 * @param oldValue provides previous value of the property
8.41 * @param newValue provides new value of the property
8.42 * @since 0.7.6
8.43 */
8.44 - public void valueHasMutated(String propName, Object oldValue, Object newValue) {
8.45 - if (ko != null) {
8.46 - ko.valueHasMutated(propName, oldValue, newValue);
8.47 - }
8.48 + public void valueHasMutated(
8.49 + final String propName, final Object oldValue, final Object newValue
8.50 + ) {
8.51 + context.execute(new Runnable() {
8.52 + @Override
8.53 + public void run() {
8.54 + if (ko != null) {
8.55 + ko.valueHasMutated(propName, oldValue, newValue);
8.56 + }
8.57 + }
8.58 + });
8.59 }
8.60
8.61 /** Initializes the associated model in the current {@link #getContext() context}.
9.1 --- a/json/src/main/java/org/netbeans/html/json/impl/JSONList.java Sun Jul 13 23:49:46 2014 +0200
9.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/JSONList.java Sun Jul 13 23:50:25 2014 +0200
9.3 @@ -174,16 +174,21 @@
9.4 }
9.5
9.6 private void notifyChange() {
9.7 - Bindings m = PropertyBindingAccessor.getBindings(proto, false);
9.8 - if (m != null) {
9.9 - m.valueHasMutated(name, null, null);
9.10 - for (String dependant : deps) {
9.11 - m.valueHasMutated(dependant, null, null);
9.12 + proto.getContext().execute(new Runnable() {
9.13 + @Override
9.14 + public void run() {
9.15 + Bindings m = PropertyBindingAccessor.getBindings(proto, false);
9.16 + if (m != null) {
9.17 + m.valueHasMutated(name, null, null);
9.18 + for (String dependant : deps) {
9.19 + m.valueHasMutated(dependant, null, null);
9.20 + }
9.21 + if (index >= 0) {
9.22 + PropertyBindingAccessor.notifyProtoChange(proto, index);
9.23 + }
9.24 + }
9.25 }
9.26 - if (index >= 0) {
9.27 - PropertyBindingAccessor.notifyProtoChange(proto, index);
9.28 - }
9.29 - }
9.30 + });
9.31 }
9.32
9.33 @Override
10.1 --- a/src/main/javadoc/overview.html Sun Jul 13 23:49:46 2014 +0200
10.2 +++ b/src/main/javadoc/overview.html Sun Jul 13 23:50:25 2014 +0200
10.3 @@ -75,6 +75,13 @@
10.4 yet the application code can be written in Java.
10.5 </p>
10.6
10.7 + <h3>What's New in Version 0.8.3?</h3>
10.8 +
10.9 + <p>
10.10 + Setters or array properties on classes generated by {@link net.java.html.json.Model}
10.11 + annotation can be accessed from any thread.
10.12 + </p>
10.13 +
10.14 <h3>What's New in Version 0.8.2?</h3>
10.15
10.16 <p>