Bringing the most recent default branch (especially the @Property MVVC) to the dew code
1.1 --- a/benchmarks/matrix-multiplication/src/main/java/org/apidesign/benchmark/matrixmul/Matrix.java Tue Jan 22 19:48:10 2013 +0100
1.2 +++ b/benchmarks/matrix-multiplication/src/main/java/org/apidesign/benchmark/matrixmul/Matrix.java Wed Jan 23 12:53:23 2013 +0100
1.3 @@ -45,7 +45,7 @@
1.4 //final int x = 10;
1.5 for (int i = 0; i < rank; i++) {
1.6 for (int j = 0; j < rank; j++) {
1.7 - data[i][j] = i + j;
1.8 + data[i][j] = 1 / (1 + i + j);
1.9 }
1.10 }
1.11 }
2.1 --- a/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java Tue Jan 22 19:48:10 2013 +0100
2.2 +++ b/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java Wed Jan 23 12:53:23 2013 +0100
2.3 @@ -27,12 +27,11 @@
2.4 * @author Jaroslav Tulach <jtulach@netbeans.org>
2.5 */
2.6 public class MatrixTest {
2.7 - public static final int ITERATION_COUNT = 10;
2.8 -
2.9 public MatrixTest() {
2.10 }
2.11
2.12 - @Compare public String tenThousandIterations() throws IOException {
2.13 + @Compare(scripting = false)
2.14 + public String tenThousandIterations() throws IOException {
2.15
2.16 Matrix m1 = new Matrix(5);
2.17 Matrix m2 = new Matrix(5);
2.18 @@ -41,12 +40,9 @@
2.19 m2.generateData();
2.20
2.21 Matrix res = null;
2.22 - for (int i = 0; i < ITERATION_COUNT; i++) {
2.23 - Matrix m = m1.multiply(m2);
2.24 - if (res != null && !res.equals(m)) {
2.25 - return "different";
2.26 - }
2.27 - res = m;
2.28 + for (int i = 0; i < 10000; i++) {
2.29 + res = m1.multiply(m2);
2.30 + m1 = res;
2.31 }
2.32
2.33 StringBuilder sb = new StringBuilder();
3.1 --- a/emul/src/main/java/java/lang/Class.java Tue Jan 22 19:48:10 2013 +0100
3.2 +++ b/emul/src/main/java/java/lang/Class.java Wed Jan 23 12:53:23 2013 +0100
3.3 @@ -1198,7 +1198,8 @@
3.4 )
3.5 native static Class getPrimitiveClass(String type);
3.6
3.7 - public boolean desiredAssertionStatus() {
3.8 - return false;
3.9 - }
3.10 + @JavaScriptBody(args = {}, body =
3.11 + "return vm.desiredAssertionStatus ? vm.desiredAssertionStatus : false;"
3.12 + )
3.13 + public native boolean desiredAssertionStatus();
3.14 }
4.1 --- a/emul/src/main/java/java/lang/Double.java Tue Jan 22 19:48:10 2013 +0100
4.2 +++ b/emul/src/main/java/java/lang/Double.java Wed Jan 23 12:53:23 2013 +0100
4.3 @@ -774,8 +774,7 @@
4.4 */
4.5 public boolean equals(Object obj) {
4.6 return (obj instanceof Double)
4.7 - && (doubleToLongBits(((Double)obj).value) ==
4.8 - doubleToLongBits(value));
4.9 + && (((Double)obj).value) == value;
4.10 }
4.11
4.12 /**
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/emul/src/main/java/java/lang/NegativeArraySizeException.java Wed Jan 23 12:53:23 2013 +0100
5.3 @@ -0,0 +1,55 @@
5.4 +/*
5.5 + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5.7 + *
5.8 + * This code is free software; you can redistribute it and/or modify it
5.9 + * under the terms of the GNU General Public License version 2 only, as
5.10 + * published by the Free Software Foundation. Oracle designates this
5.11 + * particular file as subject to the "Classpath" exception as provided
5.12 + * by Oracle in the LICENSE file that accompanied this code.
5.13 + *
5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5.17 + * version 2 for more details (a copy is included in the LICENSE file that
5.18 + * accompanied this code).
5.19 + *
5.20 + * You should have received a copy of the GNU General Public License version
5.21 + * 2 along with this work; if not, write to the Free Software Foundation,
5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5.23 + *
5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5.25 + * or visit www.oracle.com if you need additional information or have any
5.26 + * questions.
5.27 + */
5.28 +
5.29 +package java.lang;
5.30 +
5.31 +/**
5.32 + * Thrown if an application tries to create an array with negative size.
5.33 + *
5.34 + * @author unascribed
5.35 + * @since JDK1.0
5.36 + */
5.37 +public
5.38 +class NegativeArraySizeException extends RuntimeException {
5.39 + private static final long serialVersionUID = -8960118058596991861L;
5.40 +
5.41 + /**
5.42 + * Constructs a <code>NegativeArraySizeException</code> with no
5.43 + * detail message.
5.44 + */
5.45 + public NegativeArraySizeException() {
5.46 + super();
5.47 + }
5.48 +
5.49 + /**
5.50 + * Constructs a <code>NegativeArraySizeException</code> with the
5.51 + * specified detail message.
5.52 + *
5.53 + * @param s the detail message.
5.54 + */
5.55 + public NegativeArraySizeException(String s) {
5.56 + super(s);
5.57 + }
5.58 +}
6.1 --- a/emul/src/main/java/java/lang/Object.java Tue Jan 22 19:48:10 2013 +0100
6.2 +++ b/emul/src/main/java/java/lang/Object.java Wed Jan 23 12:53:23 2013 +0100
6.3 @@ -25,6 +25,7 @@
6.4
6.5 package java.lang;
6.6
6.7 +import java.lang.reflect.Array;
6.8 import org.apidesign.bck2brwsr.core.JavaScriptBody;
6.9 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
6.10
6.11 @@ -40,8 +41,13 @@
6.12 @JavaScriptPrototype(container = "Object.prototype", prototype = "new Object")
6.13 public class Object {
6.14
6.15 - @JavaScriptBody(args = {}, body = "")
6.16 - private static native void registerNatives();
6.17 + private static void registerNatives() {
6.18 + try {
6.19 + Array.get(null, 0);
6.20 + } catch (Throwable ex) {
6.21 + // ignore
6.22 + }
6.23 + }
6.24 static {
6.25 registerNatives();
6.26 }
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/emul/src/main/java/java/lang/Runnable.java Wed Jan 23 12:53:23 2013 +0100
7.3 @@ -0,0 +1,69 @@
7.4 +/*
7.5 + * Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved.
7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7.7 + *
7.8 + * This code is free software; you can redistribute it and/or modify it
7.9 + * under the terms of the GNU General Public License version 2 only, as
7.10 + * published by the Free Software Foundation. Oracle designates this
7.11 + * particular file as subject to the "Classpath" exception as provided
7.12 + * by Oracle in the LICENSE file that accompanied this code.
7.13 + *
7.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
7.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
7.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
7.17 + * version 2 for more details (a copy is included in the LICENSE file that
7.18 + * accompanied this code).
7.19 + *
7.20 + * You should have received a copy of the GNU General Public License version
7.21 + * 2 along with this work; if not, write to the Free Software Foundation,
7.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
7.23 + *
7.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
7.25 + * or visit www.oracle.com if you need additional information or have any
7.26 + * questions.
7.27 + */
7.28 +
7.29 +package java.lang;
7.30 +
7.31 +/**
7.32 + * The <code>Runnable</code> interface should be implemented by any
7.33 + * class whose instances are intended to be executed by a thread. The
7.34 + * class must define a method of no arguments called <code>run</code>.
7.35 + * <p>
7.36 + * This interface is designed to provide a common protocol for objects that
7.37 + * wish to execute code while they are active. For example,
7.38 + * <code>Runnable</code> is implemented by class <code>Thread</code>.
7.39 + * Being active simply means that a thread has been started and has not
7.40 + * yet been stopped.
7.41 + * <p>
7.42 + * In addition, <code>Runnable</code> provides the means for a class to be
7.43 + * active while not subclassing <code>Thread</code>. A class that implements
7.44 + * <code>Runnable</code> can run without subclassing <code>Thread</code>
7.45 + * by instantiating a <code>Thread</code> instance and passing itself in
7.46 + * as the target. In most cases, the <code>Runnable</code> interface should
7.47 + * be used if you are only planning to override the <code>run()</code>
7.48 + * method and no other <code>Thread</code> methods.
7.49 + * This is important because classes should not be subclassed
7.50 + * unless the programmer intends on modifying or enhancing the fundamental
7.51 + * behavior of the class.
7.52 + *
7.53 + * @author Arthur van Hoff
7.54 + * @see java.lang.Thread
7.55 + * @see java.util.concurrent.Callable
7.56 + * @since JDK1.0
7.57 + */
7.58 +public
7.59 +interface Runnable {
7.60 + /**
7.61 + * When an object implementing interface <code>Runnable</code> is used
7.62 + * to create a thread, starting the thread causes the object's
7.63 + * <code>run</code> method to be called in that separately executing
7.64 + * thread.
7.65 + * <p>
7.66 + * The general contract of the method <code>run</code> is that it may
7.67 + * take any action whatsoever.
7.68 + *
7.69 + * @see java.lang.Thread#run()
7.70 + */
7.71 + public abstract void run();
7.72 +}
8.1 --- a/emul/src/main/java/java/lang/String.java Tue Jan 22 19:48:10 2013 +0100
8.2 +++ b/emul/src/main/java/java/lang/String.java Wed Jan 23 12:53:23 2013 +0100
8.3 @@ -994,7 +994,7 @@
8.4 * @see #equalsIgnoreCase(String)
8.5 */
8.6 @JavaScriptBody(args = { "obj" }, body =
8.7 - "return obj.$instOf_java_lang_String && "
8.8 + "return obj != null && obj.$instOf_java_lang_String && "
8.9 + "this.toString() === obj.toString();"
8.10 )
8.11 public boolean equals(Object anObject) {
9.1 --- a/emul/src/main/java/java/lang/Throwable.java Tue Jan 22 19:48:10 2013 +0100
9.2 +++ b/emul/src/main/java/java/lang/Throwable.java Wed Jan 23 12:53:23 2013 +0100
9.3 @@ -26,6 +26,7 @@
9.4 package java.lang;
9.5 import java.io.*;
9.6 import org.apidesign.bck2brwsr.core.JavaScriptBody;
9.7 +import org.apidesign.bck2brwsr.core.JavaScriptOnly;
9.8
9.9 /**
9.10 * The {@code Throwable} class is the superclass of all errors and
9.11 @@ -234,6 +235,13 @@
9.12 private static final String SELF_SUPPRESSION_MESSAGE = "Self-suppression not permitted";
9.13
9.14 /** Caption for labeling causative exception stack traces */
9.15 + @JavaScriptOnly(name="toString", value="function() { return this.toString__Ljava_lang_String_2().toString(); }")
9.16 + private static void jsToString() {
9.17 + }
9.18 +
9.19 + @JavaScriptOnly(name="valueOf", value="function() { return this.toString().valueOf(); }")
9.20 + private static void jsValudOf() {
9.21 + }
9.22 private static final String CAUSE_CAPTION = "Caused by: ";
9.23
9.24 /** Caption for labeling suppressed exception stack traces */
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/emul/src/main/java/java/lang/reflect/Array.java Wed Jan 23 12:53:23 2013 +0100
10.3 @@ -0,0 +1,659 @@
10.4 +/*
10.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10.7 + *
10.8 + * This code is free software; you can redistribute it and/or modify it
10.9 + * under the terms of the GNU General Public License version 2 only, as
10.10 + * published by the Free Software Foundation. Oracle designates this
10.11 + * particular file as subject to the "Classpath" exception as provided
10.12 + * by Oracle in the LICENSE file that accompanied this code.
10.13 + *
10.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
10.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
10.17 + * version 2 for more details (a copy is included in the LICENSE file that
10.18 + * accompanied this code).
10.19 + *
10.20 + * You should have received a copy of the GNU General Public License version
10.21 + * 2 along with this work; if not, write to the Free Software Foundation,
10.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
10.23 + *
10.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
10.25 + * or visit www.oracle.com if you need additional information or have any
10.26 + * questions.
10.27 + */
10.28 +
10.29 +package java.lang.reflect;
10.30 +
10.31 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
10.32 +import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
10.33 +
10.34 +/**
10.35 + * The {@code Array} class provides static methods to dynamically create and
10.36 + * access Java arrays.
10.37 + *
10.38 + * <p>{@code Array} permits widening conversions to occur during a get or set
10.39 + * operation, but throws an {@code IllegalArgumentException} if a narrowing
10.40 + * conversion would occur.
10.41 + *
10.42 + * @author Nakul Saraiya
10.43 + */
10.44 +@JavaScriptPrototype(prototype = "new Array", container = "Array.prototype")
10.45 +public final
10.46 +class Array {
10.47 +
10.48 + /**
10.49 + * Constructor. Class Array is not instantiable.
10.50 + */
10.51 + private Array() {}
10.52 +
10.53 + /**
10.54 + * Creates a new array with the specified component type and
10.55 + * length.
10.56 + * Invoking this method is equivalent to creating an array
10.57 + * as follows:
10.58 + * <blockquote>
10.59 + * <pre>
10.60 + * int[] x = {length};
10.61 + * Array.newInstance(componentType, x);
10.62 + * </pre>
10.63 + * </blockquote>
10.64 + *
10.65 + * @param componentType the {@code Class} object representing the
10.66 + * component type of the new array
10.67 + * @param length the length of the new array
10.68 + * @return the new array
10.69 + * @exception NullPointerException if the specified
10.70 + * {@code componentType} parameter is null
10.71 + * @exception IllegalArgumentException if componentType is {@link Void#TYPE}
10.72 + * @exception NegativeArraySizeException if the specified {@code length}
10.73 + * is negative
10.74 + */
10.75 + public static Object newInstance(Class<?> componentType, int length)
10.76 + throws NegativeArraySizeException {
10.77 + if (length < 0) {
10.78 + throw new NegativeArraySizeException();
10.79 + }
10.80 + String sig = findSignature(componentType);
10.81 + return newArray(componentType.isPrimitive(), sig, length);
10.82 + }
10.83 +
10.84 + private static String findSignature(Class<?> type) {
10.85 + if (type == Integer.TYPE) {
10.86 + return "[I";
10.87 + }
10.88 + if (type == Long.TYPE) {
10.89 + return "[J";
10.90 + }
10.91 + if (type == Double.TYPE) {
10.92 + return "[D";
10.93 + }
10.94 + if (type == Float.TYPE) {
10.95 + return "[F";
10.96 + }
10.97 + if (type == Byte.TYPE) {
10.98 + return "[B";
10.99 + }
10.100 + if (type == Boolean.TYPE) {
10.101 + return "[Z";
10.102 + }
10.103 + if (type == Short.TYPE) {
10.104 + return "[S";
10.105 + }
10.106 + if (type == Character.TYPE) {
10.107 + return "[C";
10.108 + }
10.109 + if (type.getName().equals("void")) {
10.110 + throw new IllegalStateException("Can't create array for " + type);
10.111 + }
10.112 + return "[L" + type.getName() + ";";
10.113 + }
10.114 + /**
10.115 + * Creates a new array
10.116 + * with the specified component type and dimensions.
10.117 + * If {@code componentType}
10.118 + * represents a non-array class or interface, the new array
10.119 + * has {@code dimensions.length} dimensions and
10.120 + * {@code componentType} as its component type. If
10.121 + * {@code componentType} represents an array class, the
10.122 + * number of dimensions of the new array is equal to the sum
10.123 + * of {@code dimensions.length} and the number of
10.124 + * dimensions of {@code componentType}. In this case, the
10.125 + * component type of the new array is the component type of
10.126 + * {@code componentType}.
10.127 + *
10.128 + * <p>The number of dimensions of the new array must not
10.129 + * exceed the number of array dimensions supported by the
10.130 + * implementation (typically 255).
10.131 + *
10.132 + * @param componentType the {@code Class} object representing the component
10.133 + * type of the new array
10.134 + * @param dimensions an array of {@code int} representing the dimensions of
10.135 + * the new array
10.136 + * @return the new array
10.137 + * @exception NullPointerException if the specified
10.138 + * {@code componentType} argument is null
10.139 + * @exception IllegalArgumentException if the specified {@code dimensions}
10.140 + * argument is a zero-dimensional array, or if the number of
10.141 + * requested dimensions exceeds the limit on the number of array dimensions
10.142 + * supported by the implementation (typically 255), or if componentType
10.143 + * is {@link Void#TYPE}.
10.144 + * @exception NegativeArraySizeException if any of the components in
10.145 + * the specified {@code dimensions} argument is negative.
10.146 + */
10.147 + public static Object newInstance(Class<?> componentType, int... dimensions)
10.148 + throws IllegalArgumentException, NegativeArraySizeException {
10.149 + StringBuilder sig = new StringBuilder();
10.150 + for (int i = 1; i < dimensions.length; i++) {
10.151 + sig.append('[');
10.152 + }
10.153 + sig.append(findSignature(componentType));
10.154 + return multiNewArray(sig.toString(), dimensions, 0);
10.155 + }
10.156 +
10.157 + /**
10.158 + * Returns the length of the specified array object, as an {@code int}.
10.159 + *
10.160 + * @param array the array
10.161 + * @return the length of the array
10.162 + * @exception IllegalArgumentException if the object argument is not
10.163 + * an array
10.164 + */
10.165 + public static int getLength(Object array)
10.166 + throws IllegalArgumentException {
10.167 + if (!array.getClass().isArray()) {
10.168 + throw new IllegalArgumentException("Argument is not an array");
10.169 + }
10.170 + return length(array);
10.171 + }
10.172 +
10.173 + @JavaScriptBody(args = { "arr" }, body = "return arr.length;")
10.174 + private static native int length(Object arr);
10.175 +
10.176 + /**
10.177 + * Returns the value of the indexed component in the specified
10.178 + * array object. The value is automatically wrapped in an object
10.179 + * if it has a primitive type.
10.180 + *
10.181 + * @param array the array
10.182 + * @param index the index
10.183 + * @return the (possibly wrapped) value of the indexed component in
10.184 + * the specified array
10.185 + * @exception NullPointerException If the specified object is null
10.186 + * @exception IllegalArgumentException If the specified object is not
10.187 + * an array
10.188 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.189 + * argument is negative, or if it is greater than or equal to the
10.190 + * length of the specified array
10.191 + */
10.192 + public static Object get(Object array, int index)
10.193 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.194 + final Class<?> t = array.getClass().getComponentType();
10.195 + if (t.isPrimitive()) {
10.196 + return Array.fromPrimitive(t, array, index);
10.197 + } else {
10.198 + return ((Object[])array)[index];
10.199 + }
10.200 + }
10.201 +
10.202 + /**
10.203 + * Returns the value of the indexed component in the specified
10.204 + * array object, as a {@code boolean}.
10.205 + *
10.206 + * @param array the array
10.207 + * @param index the index
10.208 + * @return the value of the indexed component in the specified array
10.209 + * @exception NullPointerException If the specified object is null
10.210 + * @exception IllegalArgumentException If the specified object is not
10.211 + * an array, or if the indexed element cannot be converted to the
10.212 + * return type by an identity or widening conversion
10.213 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.214 + * argument is negative, or if it is greater than or equal to the
10.215 + * length of the specified array
10.216 + * @see Array#get
10.217 + */
10.218 + public static native boolean getBoolean(Object array, int index)
10.219 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
10.220 +
10.221 + /**
10.222 + * Returns the value of the indexed component in the specified
10.223 + * array object, as a {@code byte}.
10.224 + *
10.225 + * @param array the array
10.226 + * @param index the index
10.227 + * @return the value of the indexed component in the specified array
10.228 + * @exception NullPointerException If the specified object is null
10.229 + * @exception IllegalArgumentException If the specified object is not
10.230 + * an array, or if the indexed element cannot be converted to the
10.231 + * return type by an identity or widening conversion
10.232 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.233 + * argument is negative, or if it is greater than or equal to the
10.234 + * length of the specified array
10.235 + * @see Array#get
10.236 + */
10.237 + public static byte getByte(Object array, int index)
10.238 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.239 + if (array.getClass().getComponentType() != Byte.TYPE) {
10.240 + throw new IllegalArgumentException();
10.241 + }
10.242 + byte[] arr = (byte[]) array;
10.243 + return arr[index];
10.244 + }
10.245 +
10.246 + /**
10.247 + * Returns the value of the indexed component in the specified
10.248 + * array object, as a {@code char}.
10.249 + *
10.250 + * @param array the array
10.251 + * @param index the index
10.252 + * @return the value of the indexed component in the specified array
10.253 + * @exception NullPointerException If the specified object is null
10.254 + * @exception IllegalArgumentException If the specified object is not
10.255 + * an array, or if the indexed element cannot be converted to the
10.256 + * return type by an identity or widening conversion
10.257 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.258 + * argument is negative, or if it is greater than or equal to the
10.259 + * length of the specified array
10.260 + * @see Array#get
10.261 + */
10.262 + public static native char getChar(Object array, int index)
10.263 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
10.264 +
10.265 + /**
10.266 + * Returns the value of the indexed component in the specified
10.267 + * array object, as a {@code short}.
10.268 + *
10.269 + * @param array the array
10.270 + * @param index the index
10.271 + * @return the value of the indexed component in the specified array
10.272 + * @exception NullPointerException If the specified object is null
10.273 + * @exception IllegalArgumentException If the specified object is not
10.274 + * an array, or if the indexed element cannot be converted to the
10.275 + * return type by an identity or widening conversion
10.276 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.277 + * argument is negative, or if it is greater than or equal to the
10.278 + * length of the specified array
10.279 + * @see Array#get
10.280 + */
10.281 + public static short getShort(Object array, int index)
10.282 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.283 + final Class<?> t = array.getClass().getComponentType();
10.284 + if (t == Short.TYPE) {
10.285 + short[] arr = (short[]) array;
10.286 + return arr[index];
10.287 + }
10.288 + return getByte(array, index);
10.289 + }
10.290 +
10.291 + /**
10.292 + * Returns the value of the indexed component in the specified
10.293 + * array object, as an {@code int}.
10.294 + *
10.295 + * @param array the array
10.296 + * @param index the index
10.297 + * @return the value of the indexed component in the specified array
10.298 + * @exception NullPointerException If the specified object is null
10.299 + * @exception IllegalArgumentException If the specified object is not
10.300 + * an array, or if the indexed element cannot be converted to the
10.301 + * return type by an identity or widening conversion
10.302 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.303 + * argument is negative, or if it is greater than or equal to the
10.304 + * length of the specified array
10.305 + * @see Array#get
10.306 + */
10.307 + public static int getInt(Object array, int index)
10.308 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.309 + final Class<?> t = array.getClass().getComponentType();
10.310 + if (t == Integer.TYPE) {
10.311 + int[] arr = (int[]) array;
10.312 + return arr[index];
10.313 + }
10.314 + return getShort(array, index);
10.315 + }
10.316 +
10.317 + /**
10.318 + * Returns the value of the indexed component in the specified
10.319 + * array object, as a {@code long}.
10.320 + *
10.321 + * @param array the array
10.322 + * @param index the index
10.323 + * @return the value of the indexed component in the specified array
10.324 + * @exception NullPointerException If the specified object is null
10.325 + * @exception IllegalArgumentException If the specified object is not
10.326 + * an array, or if the indexed element cannot be converted to the
10.327 + * return type by an identity or widening conversion
10.328 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.329 + * argument is negative, or if it is greater than or equal to the
10.330 + * length of the specified array
10.331 + * @see Array#get
10.332 + */
10.333 + public static long getLong(Object array, int index)
10.334 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.335 + final Class<?> t = array.getClass().getComponentType();
10.336 + if (t == Long.TYPE) {
10.337 + long[] arr = (long[]) array;
10.338 + return arr[index];
10.339 + }
10.340 + return getInt(array, index);
10.341 + }
10.342 +
10.343 + /**
10.344 + * Returns the value of the indexed component in the specified
10.345 + * array object, as a {@code float}.
10.346 + *
10.347 + * @param array the array
10.348 + * @param index the index
10.349 + * @return the value of the indexed component in the specified array
10.350 + * @exception NullPointerException If the specified object is null
10.351 + * @exception IllegalArgumentException If the specified object is not
10.352 + * an array, or if the indexed element cannot be converted to the
10.353 + * return type by an identity or widening conversion
10.354 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.355 + * argument is negative, or if it is greater than or equal to the
10.356 + * length of the specified array
10.357 + * @see Array#get
10.358 + */
10.359 + public static float getFloat(Object array, int index)
10.360 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.361 + final Class<?> t = array.getClass().getComponentType();
10.362 + if (t == Float.TYPE) {
10.363 + float[] arr = (float[]) array;
10.364 + return arr[index];
10.365 + }
10.366 + return getLong(array, index);
10.367 + }
10.368 +
10.369 + /**
10.370 + * Returns the value of the indexed component in the specified
10.371 + * array object, as a {@code double}.
10.372 + *
10.373 + * @param array the array
10.374 + * @param index the index
10.375 + * @return the value of the indexed component in the specified array
10.376 + * @exception NullPointerException If the specified object is null
10.377 + * @exception IllegalArgumentException If the specified object is not
10.378 + * an array, or if the indexed element cannot be converted to the
10.379 + * return type by an identity or widening conversion
10.380 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.381 + * argument is negative, or if it is greater than or equal to the
10.382 + * length of the specified array
10.383 + * @see Array#get
10.384 + */
10.385 + public static double getDouble(Object array, int index)
10.386 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.387 + final Class<?> t = array.getClass().getComponentType();
10.388 + if (t == Double.TYPE) {
10.389 + double[] arr = (double[]) array;
10.390 + return arr[index];
10.391 + }
10.392 + return getFloat(array, index);
10.393 + }
10.394 +
10.395 + /**
10.396 + * Sets the value of the indexed component of the specified array
10.397 + * object to the specified new value. The new value is first
10.398 + * automatically unwrapped if the array has a primitive component
10.399 + * type.
10.400 + * @param array the array
10.401 + * @param index the index into the array
10.402 + * @param value the new value of the indexed component
10.403 + * @exception NullPointerException If the specified object argument
10.404 + * is null
10.405 + * @exception IllegalArgumentException If the specified object argument
10.406 + * is not an array, or if the array component type is primitive and
10.407 + * an unwrapping conversion fails
10.408 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.409 + * argument is negative, or if it is greater than or equal to
10.410 + * the length of the specified array
10.411 + */
10.412 + public static void set(Object array, int index, Object value)
10.413 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.414 + if (array.getClass().getComponentType().isPrimitive()) {
10.415 + throw new IllegalArgumentException();
10.416 + } else {
10.417 + Object[] arr = (Object[])array;
10.418 + arr[index] = value;
10.419 + }
10.420 + }
10.421 +
10.422 + /**
10.423 + * Sets the value of the indexed component of the specified array
10.424 + * object to the specified {@code boolean} value.
10.425 + * @param array the array
10.426 + * @param index the index into the array
10.427 + * @param z the new value of the indexed component
10.428 + * @exception NullPointerException If the specified object argument
10.429 + * is null
10.430 + * @exception IllegalArgumentException If the specified object argument
10.431 + * is not an array, or if the specified value cannot be converted
10.432 + * to the underlying array's component type by an identity or a
10.433 + * primitive widening conversion
10.434 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.435 + * argument is negative, or if it is greater than or equal to
10.436 + * the length of the specified array
10.437 + * @see Array#set
10.438 + */
10.439 + public static native void setBoolean(Object array, int index, boolean z)
10.440 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
10.441 +
10.442 + /**
10.443 + * Sets the value of the indexed component of the specified array
10.444 + * object to the specified {@code byte} value.
10.445 + * @param array the array
10.446 + * @param index the index into the array
10.447 + * @param b the new value of the indexed component
10.448 + * @exception NullPointerException If the specified object argument
10.449 + * is null
10.450 + * @exception IllegalArgumentException If the specified object argument
10.451 + * is not an array, or if the specified value cannot be converted
10.452 + * to the underlying array's component type by an identity or a
10.453 + * primitive widening conversion
10.454 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.455 + * argument is negative, or if it is greater than or equal to
10.456 + * the length of the specified array
10.457 + * @see Array#set
10.458 + */
10.459 + public static void setByte(Object array, int index, byte b)
10.460 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.461 + Class<?> t = array.getClass().getComponentType();
10.462 + if (t == Byte.TYPE) {
10.463 + byte[] arr = (byte[]) array;
10.464 + arr[index] = b;
10.465 + } else {
10.466 + setShort(array, index, b);
10.467 + }
10.468 + }
10.469 +
10.470 + /**
10.471 + * Sets the value of the indexed component of the specified array
10.472 + * object to the specified {@code char} value.
10.473 + * @param array the array
10.474 + * @param index the index into the array
10.475 + * @param c the new value of the indexed component
10.476 + * @exception NullPointerException If the specified object argument
10.477 + * is null
10.478 + * @exception IllegalArgumentException If the specified object argument
10.479 + * is not an array, or if the specified value cannot be converted
10.480 + * to the underlying array's component type by an identity or a
10.481 + * primitive widening conversion
10.482 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.483 + * argument is negative, or if it is greater than or equal to
10.484 + * the length of the specified array
10.485 + * @see Array#set
10.486 + */
10.487 + public static native void setChar(Object array, int index, char c)
10.488 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException;
10.489 +
10.490 + /**
10.491 + * Sets the value of the indexed component of the specified array
10.492 + * object to the specified {@code short} value.
10.493 + * @param array the array
10.494 + * @param index the index into the array
10.495 + * @param s the new value of the indexed component
10.496 + * @exception NullPointerException If the specified object argument
10.497 + * is null
10.498 + * @exception IllegalArgumentException If the specified object argument
10.499 + * is not an array, or if the specified value cannot be converted
10.500 + * to the underlying array's component type by an identity or a
10.501 + * primitive widening conversion
10.502 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.503 + * argument is negative, or if it is greater than or equal to
10.504 + * the length of the specified array
10.505 + * @see Array#set
10.506 + */
10.507 + public static void setShort(Object array, int index, short s)
10.508 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.509 + Class<?> t = array.getClass().getComponentType();
10.510 + if (t == Short.TYPE) {
10.511 + short[] arr = (short[]) array;
10.512 + arr[index] = s;
10.513 + } else {
10.514 + setInt(array, index, s);
10.515 + }
10.516 +
10.517 + }
10.518 +
10.519 + /**
10.520 + * Sets the value of the indexed component of the specified array
10.521 + * object to the specified {@code int} value.
10.522 + * @param array the array
10.523 + * @param index the index into the array
10.524 + * @param i the new value of the indexed component
10.525 + * @exception NullPointerException If the specified object argument
10.526 + * is null
10.527 + * @exception IllegalArgumentException If the specified object argument
10.528 + * is not an array, or if the specified value cannot be converted
10.529 + * to the underlying array's component type by an identity or a
10.530 + * primitive widening conversion
10.531 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.532 + * argument is negative, or if it is greater than or equal to
10.533 + * the length of the specified array
10.534 + * @see Array#set
10.535 + */
10.536 + public static void setInt(Object array, int index, int i)
10.537 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.538 + Class<?> t = array.getClass().getComponentType();
10.539 + if (t == Integer.TYPE) {
10.540 + long[] arr = (long[]) array;
10.541 + arr[index] = i;
10.542 + } else {
10.543 + setLong(array, index, i);
10.544 + }
10.545 + }
10.546 +
10.547 + /**
10.548 + * Sets the value of the indexed component of the specified array
10.549 + * object to the specified {@code long} value.
10.550 + * @param array the array
10.551 + * @param index the index into the array
10.552 + * @param l the new value of the indexed component
10.553 + * @exception NullPointerException If the specified object argument
10.554 + * is null
10.555 + * @exception IllegalArgumentException If the specified object argument
10.556 + * is not an array, or if the specified value cannot be converted
10.557 + * to the underlying array's component type by an identity or a
10.558 + * primitive widening conversion
10.559 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.560 + * argument is negative, or if it is greater than or equal to
10.561 + * the length of the specified array
10.562 + * @see Array#set
10.563 + */
10.564 + public static void setLong(Object array, int index, long l)
10.565 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.566 + Class<?> t = array.getClass().getComponentType();
10.567 + if (t == Long.TYPE) {
10.568 + long[] arr = (long[]) array;
10.569 + arr[index] = l;
10.570 + } else {
10.571 + setFloat(array, index, l);
10.572 + }
10.573 + }
10.574 +
10.575 + /**
10.576 + * Sets the value of the indexed component of the specified array
10.577 + * object to the specified {@code float} value.
10.578 + * @param array the array
10.579 + * @param index the index into the array
10.580 + * @param f the new value of the indexed component
10.581 + * @exception NullPointerException If the specified object argument
10.582 + * is null
10.583 + * @exception IllegalArgumentException If the specified object argument
10.584 + * is not an array, or if the specified value cannot be converted
10.585 + * to the underlying array's component type by an identity or a
10.586 + * primitive widening conversion
10.587 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.588 + * argument is negative, or if it is greater than or equal to
10.589 + * the length of the specified array
10.590 + * @see Array#set
10.591 + */
10.592 + public static void setFloat(Object array, int index, float f)
10.593 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.594 + Class<?> t = array.getClass().getComponentType();
10.595 + if (t == Float.TYPE) {
10.596 + float[] arr = (float[])array;
10.597 + arr[index] = f;
10.598 + } else {
10.599 + setDouble(array, index, f);
10.600 + }
10.601 + }
10.602 +
10.603 + /**
10.604 + * Sets the value of the indexed component of the specified array
10.605 + * object to the specified {@code double} value.
10.606 + * @param array the array
10.607 + * @param index the index into the array
10.608 + * @param d the new value of the indexed component
10.609 + * @exception NullPointerException If the specified object argument
10.610 + * is null
10.611 + * @exception IllegalArgumentException If the specified object argument
10.612 + * is not an array, or if the specified value cannot be converted
10.613 + * to the underlying array's component type by an identity or a
10.614 + * primitive widening conversion
10.615 + * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
10.616 + * argument is negative, or if it is greater than or equal to
10.617 + * the length of the specified array
10.618 + * @see Array#set
10.619 + */
10.620 + public static void setDouble(Object array, int index, double d)
10.621 + throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
10.622 + Class<?> t = array.getClass().getComponentType();
10.623 + if (t == Double.TYPE) {
10.624 + double[] arr = (double[])array;
10.625 + arr[index] = d;
10.626 + } else {
10.627 + throw new IllegalArgumentException("argument type mismatch");
10.628 + }
10.629 + }
10.630 +
10.631 + /*
10.632 + * Private
10.633 + */
10.634 +
10.635 + @JavaScriptBody(args = { "primitive", "sig", "length" }, body =
10.636 + "var arr = new Array(length);\n"
10.637 + + "var value = primitive ? 0 : null;\n"
10.638 + + "for(var i = 0; i < length; i++) arr[i] = value;\n"
10.639 + + "arr.jvmName = sig;\n"
10.640 + + "return arr;"
10.641 + )
10.642 + private static native Object newArray(boolean primitive, String sig, int length);
10.643 +
10.644 + private static Object multiNewArray(String sig, int[] dims, int index)
10.645 + throws IllegalArgumentException, NegativeArraySizeException {
10.646 + if (dims.length == index + 1) {
10.647 + return newArray(sig.length() == 2, sig, dims[index]);
10.648 + }
10.649 + Object[] arr = (Object[]) newArray(false, sig, dims[index]);
10.650 + String compsig = sig.substring(1);
10.651 + for (int i = 0; i < arr.length; i++) {
10.652 + arr[i] = multiNewArray(compsig, dims, index + 1);
10.653 + }
10.654 + return arr;
10.655 + }
10.656 + private static Object fromPrimitive(Class<?> t, Object array, int index) {
10.657 + return Method.fromPrimitive(t, atArray(array, index));
10.658 + }
10.659 +
10.660 + @JavaScriptBody(args = { "array", "index" }, body = "return array[index]")
10.661 + private static native Object atArray(Object array, int index);
10.662 +}
11.1 --- a/emul/src/main/java/java/lang/reflect/Method.java Tue Jan 22 19:48:10 2013 +0100
11.2 +++ b/emul/src/main/java/java/lang/reflect/Method.java Wed Jan 23 12:53:23 2013 +0100
11.3 @@ -537,7 +537,7 @@
11.4 )
11.5 private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args);
11.6
11.7 - private static Object fromPrimitive(Class<?> type, Object o) {
11.8 + static Object fromPrimitive(Class<?> type, Object o) {
11.9 if (type == Integer.TYPE) {
11.10 return fromRaw(Integer.class, "valueOf__Ljava_lang_Integer_2I", o);
11.11 }
12.1 --- a/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Tue Jan 22 19:48:10 2013 +0100
12.2 +++ b/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Wed Jan 23 12:53:23 2013 +0100
12.3 @@ -1,12 +1,7 @@
12.4 -// initialize methods on String constants
12.5 +// initialize methods on arrays and String constants
12.6 +vm.java_lang_reflect_Array(false);
12.7 vm.java_lang_String(false);
12.8
12.9 -// we need initialized arrays
12.10 -Array.prototype.initWith = function(sig, value) {
12.11 - for(var i = 0; i < this.length; i++) this[i] = value;
12.12 - this.jvmName = sig;
12.13 - return this;
12.14 -};
12.15 Array.prototype.at = function(indx, value) {
12.16 if (indx < 0 || indx > this.length) {
12.17 var e = vm.java_lang_ArrayIndexOutOfBoundsException(true);
13.1 --- a/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Tue Jan 22 19:48:10 2013 +0100
13.2 +++ b/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Wed Jan 23 12:53:23 2013 +0100
13.3 @@ -123,7 +123,7 @@
13.4 }
13.5
13.6 final int length = methodSignature.length();
13.7 - int skipType = 0;
13.8 + boolean skipType = false;
13.9 int argType;
13.10 for (int i = 1; i < length; ++i) {
13.11 switch (methodSignature.charAt(i)) {
13.12 @@ -156,10 +156,10 @@
13.13 // not interested in the return value type
13.14 return argTypes;
13.15 case '[':
13.16 - if (skipType == 0) {
13.17 + if (!skipType) {
13.18 argTypes.add(ITEM_Object);
13.19 + skipType = true;
13.20 }
13.21 - ++skipType;
13.22 continue;
13.23
13.24 default:
13.25 @@ -167,10 +167,10 @@
13.26 "Invalid method signature");
13.27 }
13.28
13.29 - if (skipType == 0) {
13.30 + if (!skipType) {
13.31 argTypes.add(argType);
13.32 } else {
13.33 - --skipType;
13.34 + skipType = false;
13.35 }
13.36 }
13.37
14.1 --- a/javaquery/api/pom.xml Tue Jan 22 19:48:10 2013 +0100
14.2 +++ b/javaquery/api/pom.xml Wed Jan 23 12:53:23 2013 +0100
14.3 @@ -64,5 +64,11 @@
14.4 <type>jar</type>
14.5 <scope>test</scope>
14.6 </dependency>
14.7 + <dependency>
14.8 + <groupId>${project.groupId}</groupId>
14.9 + <artifactId>vmtest</artifactId>
14.10 + <version>${project.version}</version>
14.11 + <scope>test</scope>
14.12 + </dependency>
14.13 </dependencies>
14.14 </project>
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/Knockout.java Wed Jan 23 12:53:23 2013 +0100
15.3 @@ -0,0 +1,93 @@
15.4 +/**
15.5 + * Back 2 Browser Bytecode Translator
15.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
15.7 + *
15.8 + * This program is free software: you can redistribute it and/or modify
15.9 + * it under the terms of the GNU General Public License as published by
15.10 + * the Free Software Foundation, version 2 of the License.
15.11 + *
15.12 + * This program is distributed in the hope that it will be useful,
15.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
15.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15.15 + * GNU General Public License for more details.
15.16 + *
15.17 + * You should have received a copy of the GNU General Public License
15.18 + * along with this program. Look for COPYING file in the top folder.
15.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
15.20 + */
15.21 +package org.apidesign.bck2brwsr.htmlpage;
15.22 +
15.23 +import java.lang.reflect.Method;
15.24 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
15.25 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
15.26 +
15.27 +/** Provides binding between models and
15.28 + *
15.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
15.30 + */
15.31 +@ExtraJavaScript(resource = "/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js")
15.32 +public class Knockout {
15.33 + /** used by tests */
15.34 + static Knockout next;
15.35 +
15.36 + Knockout() {
15.37 + }
15.38 +
15.39 + public static <M> Knockout applyBindings(
15.40 + Class<M> modelClass, M model, String[] propsGettersAndSetters
15.41 + ) {
15.42 + Knockout bindings = next;
15.43 + next = null;
15.44 + if (bindings == null) {
15.45 + bindings = new Knockout();
15.46 + }
15.47 + for (int i = 0; i < propsGettersAndSetters.length; i += 4) {
15.48 + try {
15.49 + Method getter = modelClass.getMethod(propsGettersAndSetters[i + 3]);
15.50 + bind(bindings, model, propsGettersAndSetters[i],
15.51 + propsGettersAndSetters[i + 1],
15.52 + propsGettersAndSetters[i + 2],
15.53 + getter.getReturnType().isPrimitive()
15.54 + );
15.55 + } catch (NoSuchMethodException ex) {
15.56 + throw new IllegalStateException(ex.getMessage());
15.57 + }
15.58 + }
15.59 + applyBindings(bindings);
15.60 + return bindings;
15.61 + }
15.62 +
15.63 + @JavaScriptBody(args = { "prop" }, body =
15.64 + "this[prop].valueHasMutated();"
15.65 + )
15.66 + public void valueHasMutated(String prop) {
15.67 + }
15.68 +
15.69 +
15.70 + @JavaScriptBody(args = { "id", "ev" }, body = "ko.utils.triggerEvent(window.document.getElementById(id), ev.substring(2));")
15.71 + public static void triggerEvent(String id, String ev) {
15.72 + }
15.73 +
15.74 + @JavaScriptBody(args = { "bindings", "model", "prop", "getter", "setter", "primitive" }, body =
15.75 + "var bnd = {\n"
15.76 + + " read: function() {\n"
15.77 + + " var v = model[getter]();\n"
15.78 + + " return v;\n"
15.79 + + " },\n"
15.80 + + " owner: bindings\n"
15.81 + + "};\n"
15.82 + + "if (setter != null) {\n"
15.83 + + " bnd.write = function(val) {\n"
15.84 + + " model[setter](primitive ? new Number(val) : val);\n"
15.85 + + " };\n"
15.86 + + "}\n"
15.87 + + "bindings[prop] = ko.computed(bnd);"
15.88 + )
15.89 + private static void bind(
15.90 + Object bindings, Object model, String prop, String getter, String setter, boolean primitive
15.91 + ) {
15.92 + }
15.93 +
15.94 + @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);")
15.95 + private static void applyBindings(Object bindings) {}
15.96 +}
16.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Tue Jan 22 19:48:10 2013 +0100
16.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Wed Jan 23 12:53:23 2013 +0100
16.3 @@ -22,9 +22,13 @@
16.4 import java.io.OutputStreamWriter;
16.5 import java.io.Writer;
16.6 import java.util.ArrayList;
16.7 +import java.util.Collection;
16.8 import java.util.Collections;
16.9 +import java.util.HashMap;
16.10 +import java.util.LinkedHashSet;
16.11 import java.util.List;
16.12 import java.util.Locale;
16.13 +import java.util.Map;
16.14 import java.util.Set;
16.15 import javax.annotation.processing.AbstractProcessor;
16.16 import javax.annotation.processing.Completion;
16.17 @@ -39,12 +43,16 @@
16.18 import javax.lang.model.element.Modifier;
16.19 import javax.lang.model.element.PackageElement;
16.20 import javax.lang.model.element.TypeElement;
16.21 +import javax.lang.model.element.VariableElement;
16.22 +import javax.lang.model.type.MirroredTypeException;
16.23 import javax.lang.model.type.TypeMirror;
16.24 import javax.tools.Diagnostic;
16.25 import javax.tools.FileObject;
16.26 import javax.tools.StandardLocation;
16.27 +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
16.28 import org.apidesign.bck2brwsr.htmlpage.api.On;
16.29 import org.apidesign.bck2brwsr.htmlpage.api.Page;
16.30 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
16.31 import org.openide.util.lookup.ServiceProvider;
16.32
16.33 /** Annotation processor to process an XHTML page and generate appropriate
16.34 @@ -89,19 +97,44 @@
16.35 try {
16.36 w.append("package " + pkg + ";\n");
16.37 w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n");
16.38 - w.append("class ").append(className).append(" {\n");
16.39 + w.append("final class ").append(className).append(" {\n");
16.40 + w.append(" private boolean locked;\n");
16.41 + if (!initializeOnClick(className, (TypeElement) e, w, pp)) {
16.42 + return false;
16.43 + }
16.44 for (String id : pp.ids()) {
16.45 String tag = pp.tagNameForId(id);
16.46 String type = type(tag);
16.47 - w.append(" ").append("public static final ").
16.48 + w.append(" ").append("public final ").
16.49 append(type).append(' ').append(cnstnt(id)).append(" = new ").
16.50 append(type).append("(\"").append(id).append("\");\n");
16.51 }
16.52 - w.append(" static {\n");
16.53 - if (!initializeOnClick(pe, w, pp)) {
16.54 - return false;
16.55 + List<String> propsGetSet = new ArrayList<String>();
16.56 + Map<String,Collection<String>> propsDeps = new HashMap<String, Collection<String>>();
16.57 + generateComputedProperties(w, e.getEnclosedElements(), propsGetSet, propsDeps);
16.58 + generateProperties(w, p.properties(), propsGetSet, propsDeps);
16.59 + w.append(" private org.apidesign.bck2brwsr.htmlpage.Knockout ko;\n");
16.60 + if (!propsGetSet.isEmpty()) {
16.61 + w.write("public " + className + " applyBindings() {\n");
16.62 + w.write(" ko = org.apidesign.bck2brwsr.htmlpage.Knockout.applyBindings(");
16.63 + w.write(className + ".class, this, ");
16.64 + w.write("new String[] {\n");
16.65 + String sep = "";
16.66 + for (String n : propsGetSet) {
16.67 + w.write(sep);
16.68 + if (n == null) {
16.69 + w.write(" null");
16.70 + } else {
16.71 + w.write(" \"" + n + "\"");
16.72 + }
16.73 + sep = ",\n";
16.74 + }
16.75 + w.write("\n });\n return this;\n}\n");
16.76 +
16.77 + w.write("public void triggerEvent(Element e, OnEvent ev) {\n");
16.78 + w.write(" org.apidesign.bck2brwsr.htmlpage.Knockout.triggerEvent(e.getId(), ev.getElementPropertyName());\n");
16.79 + w.write("}\n");
16.80 }
16.81 - w.append(" }\n");
16.82 w.append("}\n");
16.83 } finally {
16.84 w.close();
16.85 @@ -134,21 +167,31 @@
16.86 if (tag.equals("input")) {
16.87 return "Input";
16.88 }
16.89 + if (tag.equals("canvas")) {
16.90 + return "Canvas";
16.91 + }
16.92 + if (tag.equals("img")) {
16.93 + return "Image";
16.94 + }
16.95 return "Element";
16.96 }
16.97
16.98 private static String cnstnt(String id) {
16.99 - return id.toUpperCase(Locale.ENGLISH).replace('.', '_');
16.100 + return id.toUpperCase(Locale.ENGLISH).replace('.', '_').replace('-', '_');
16.101 }
16.102
16.103 - private boolean initializeOnClick(PackageElement pe, Writer w, ProcessPage pp) throws IOException {
16.104 + private boolean initializeOnClick(
16.105 + String className, TypeElement type, Writer w, ProcessPage pp
16.106 + ) throws IOException {
16.107 TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
16.108 - for (Element clazz : pe.getEnclosedElements()) {
16.109 - if (clazz.getKind() != ElementKind.CLASS) {
16.110 - continue;
16.111 - }
16.112 - TypeElement type = (TypeElement)clazz;
16.113 - for (Element method : clazz.getEnclosedElements()) {
16.114 + { //for (Element clazz : pe.getEnclosedElements()) {
16.115 + // if (clazz.getKind() != ElementKind.CLASS) {
16.116 + // continue;
16.117 + // }
16.118 + w.append(" public ").append(className).append("() {\n");
16.119 + StringBuilder dispatch = new StringBuilder();
16.120 + int dispatchCnt = 0;
16.121 + for (Element method : type.getEnclosedElements()) {
16.122 On oc = method.getAnnotation(On.class);
16.123 if (oc != null) {
16.124 for (String id : oc.id()) {
16.125 @@ -157,15 +200,33 @@
16.126 return false;
16.127 }
16.128 ExecutableElement ee = (ExecutableElement)method;
16.129 - boolean hasParam;
16.130 - if (ee.getParameters().isEmpty()) {
16.131 - hasParam = false;
16.132 - } else {
16.133 - if (ee.getParameters().size() != 1 || ee.getParameters().get(0).asType() != stringType) {
16.134 - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method should either have no arguments or one String argument", ee);
16.135 + StringBuilder params = new StringBuilder();
16.136 + {
16.137 + boolean first = true;
16.138 + for (VariableElement ve : ee.getParameters()) {
16.139 + if (!first) {
16.140 + params.append(", ");
16.141 + }
16.142 + first = false;
16.143 + if (ve.asType() == stringType) {
16.144 + params.append('"').append(id).append('"');
16.145 + continue;
16.146 + }
16.147 + String rn = ve.asType().toString();
16.148 + int last = rn.lastIndexOf('.');
16.149 + if (last >= 0) {
16.150 + rn = rn.substring(last + 1);
16.151 + }
16.152 + if (rn.equals(className)) {
16.153 + params.append(className).append(".this");
16.154 + continue;
16.155 + }
16.156 + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
16.157 + "@On method can only accept String or " + className + " arguments",
16.158 + ee
16.159 + );
16.160 return false;
16.161 }
16.162 - hasParam = true;
16.163 }
16.164 if (!ee.getModifiers().contains(Modifier.STATIC)) {
16.165 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@On method has to be static", ee);
16.166 @@ -176,17 +237,33 @@
16.167 return false;
16.168 }
16.169 w.append(" OnEvent." + oc.event()).append(".of(").append(cnstnt(id)).
16.170 - append(").perform(new Runnable() { public void run() {\n");
16.171 - w.append(" ").append(type.getSimpleName().toString()).
16.172 - append('.').append(ee.getSimpleName()).append("(");
16.173 - if (hasParam) {
16.174 - w.append("\"").append(id).append("\"");
16.175 - }
16.176 - w.append(");\n");
16.177 - w.append(" }});\n");
16.178 - }
16.179 + append(").perform(new OnDispatch(" + dispatchCnt + "));\n");
16.180 +
16.181 + dispatch.
16.182 + append(" case ").append(dispatchCnt).append(": ").
16.183 + append(type.getSimpleName().toString()).
16.184 + append('.').append(ee.getSimpleName()).append("(").
16.185 + append(params).
16.186 + append("); break;\n");
16.187 +
16.188 + dispatchCnt++;
16.189 + }
16.190 }
16.191 }
16.192 + w.append(" }\n");
16.193 + if (dispatchCnt > 0) {
16.194 + w.append("class OnDispatch implements Runnable {\n");
16.195 + w.append(" private final int dispatch;\n");
16.196 + w.append(" OnDispatch(int d) { dispatch = d; }\n");
16.197 + w.append(" public void run() {\n");
16.198 + w.append(" switch (dispatch) {\n");
16.199 + w.append(dispatch);
16.200 + w.append(" }\n");
16.201 + w.append(" }\n");
16.202 + w.append("}\n");
16.203 + }
16.204 +
16.205 +
16.206 }
16.207 return true;
16.208 }
16.209 @@ -233,4 +310,126 @@
16.210 }
16.211 return e.getEnclosingElement();
16.212 }
16.213 +
16.214 + private static void generateProperties(
16.215 + Writer w, Property[] properties, Collection<String> props,
16.216 + Map<String,Collection<String>> deps
16.217 + ) throws IOException {
16.218 + for (Property p : properties) {
16.219 + final String tn = typeName(p);
16.220 + String[] gs = toGetSet(p.name(), tn);
16.221 +
16.222 + w.write("private " + tn + " prop_" + p.name() + ";\n");
16.223 + w.write("public " + tn + " " + gs[0] + "() {\n");
16.224 + w.write(" if (locked) throw new IllegalStateException();\n");
16.225 + w.write(" return prop_" + p.name() + ";\n");
16.226 + w.write("}\n");
16.227 + w.write("public void " + gs[1] + "(" + tn + " v) {\n");
16.228 + w.write(" if (locked) throw new IllegalStateException();\n");
16.229 + w.write(" prop_" + p.name() + " = v;\n");
16.230 + w.write(" if (ko != null) {\n");
16.231 + w.write(" ko.valueHasMutated(\"" + p.name() + "\");\n");
16.232 + final Collection<String> dependants = deps.get(p.name());
16.233 + if (dependants != null) {
16.234 + for (String depProp : dependants) {
16.235 + w.write(" ko.valueHasMutated(\"" + depProp + "\");\n");
16.236 + }
16.237 + }
16.238 + w.write(" }\n");
16.239 + w.write("}\n");
16.240 +
16.241 + props.add(p.name());
16.242 + props.add(gs[2]);
16.243 + props.add(gs[3]);
16.244 + props.add(gs[0]);
16.245 + }
16.246 + }
16.247 +
16.248 + private boolean generateComputedProperties(
16.249 + Writer w, Collection<? extends Element> arr, Collection<String> props,
16.250 + Map<String,Collection<String>> deps
16.251 + ) throws IOException {
16.252 + for (Element e : arr) {
16.253 + if (e.getKind() != ElementKind.METHOD) {
16.254 + continue;
16.255 + }
16.256 + if (e.getAnnotation(ComputedProperty.class) == null) {
16.257 + continue;
16.258 + }
16.259 + ExecutableElement ee = (ExecutableElement)e;
16.260 + final String tn = ee.getReturnType().toString();
16.261 + final String sn = ee.getSimpleName().toString();
16.262 + String[] gs = toGetSet(sn, tn);
16.263 +
16.264 + w.write("public " + tn + " " + gs[0] + "() {\n");
16.265 + w.write(" if (locked) throw new IllegalStateException();\n");
16.266 + int arg = 0;
16.267 + for (VariableElement pe : ee.getParameters()) {
16.268 + final String dn = pe.getSimpleName().toString();
16.269 + final String dt = pe.asType().toString();
16.270 + String[] call = toGetSet(dn, dt);
16.271 + w.write(" " + dt + " arg" + (++arg) + " = ");
16.272 + w.write(call[0] + "();\n");
16.273 +
16.274 + Collection<String> depends = deps.get(dn);
16.275 + if (depends == null) {
16.276 + depends = new LinkedHashSet<String>();
16.277 + deps.put(dn, depends);
16.278 + }
16.279 + depends.add(sn);
16.280 + }
16.281 + w.write(" try {\n");
16.282 + w.write(" locked = true;\n");
16.283 + w.write(" return " + e.getEnclosingElement().getSimpleName() + '.' + e.getSimpleName() + "(");
16.284 + String sep = "";
16.285 + for (int i = 1; i <= arg; i++) {
16.286 + w.write(sep);
16.287 + w.write("arg" + i);
16.288 + sep = ", ";
16.289 + }
16.290 + w.write(");\n");
16.291 + w.write(" } finally {\n");
16.292 + w.write(" locked = false;\n");
16.293 + w.write(" }\n");
16.294 + w.write("}\n");
16.295 +
16.296 + props.add(e.getSimpleName().toString());
16.297 + props.add(gs[2]);
16.298 + props.add(null);
16.299 + props.add(gs[0]);
16.300 + }
16.301 +
16.302 + return true;
16.303 + }
16.304 +
16.305 + private static String[] toGetSet(String name, String type) {
16.306 + String n = Character.toUpperCase(name.charAt(0)) + name.substring(1);
16.307 + String bck2brwsrType = "L" + type.replace('.', '_') + "_2";
16.308 + if ("int".equals(type)) {
16.309 + bck2brwsrType = "I";
16.310 + }
16.311 + if ("double".equals(type)) {
16.312 + bck2brwsrType = "D";
16.313 + }
16.314 + String pref = "get";
16.315 + if ("boolean".equals(type)) {
16.316 + pref = "is";
16.317 + bck2brwsrType = "Z";
16.318 + }
16.319 + final String nu = n.replace('.', '_');
16.320 + return new String[]{
16.321 + pref + n,
16.322 + "set" + n,
16.323 + pref + nu + "__" + bck2brwsrType,
16.324 + "set" + nu + "__V" + bck2brwsrType
16.325 + };
16.326 + }
16.327 +
16.328 + private static String typeName(Property p) {
16.329 + try {
16.330 + return p.type().getName();
16.331 + } catch (MirroredTypeException ex) {
16.332 + return ex.getTypeMirror().toString();
16.333 + }
16.334 + }
16.335 }
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Canvas.java Wed Jan 23 12:53:23 2013 +0100
17.3 @@ -0,0 +1,61 @@
17.4 +/**
17.5 + * Back 2 Browser Bytecode Translator
17.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
17.7 + *
17.8 + * This program is free software: you can redistribute it and/or modify
17.9 + * it under the terms of the GNU General Public License as published by
17.10 + * the Free Software Foundation, version 2 of the License.
17.11 + *
17.12 + * This program is distributed in the hope that it will be useful,
17.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
17.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17.15 + * GNU General Public License for more details.
17.16 + *
17.17 + * You should have received a copy of the GNU General Public License
17.18 + * along with this program. Look for COPYING file in the top folder.
17.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
17.20 + */
17.21 +package org.apidesign.bck2brwsr.htmlpage.api;
17.22 +
17.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
17.24 +
17.25 +/**
17.26 + *
17.27 + * @author Anton Epple <toni.epple@eppleton.de>
17.28 + */
17.29 +public class Canvas extends Element {
17.30 +
17.31 + public Canvas(String id) {
17.32 + super(id);
17.33 + }
17.34 +
17.35 + public void setHeight(int height) {
17.36 + setAttribute(this, "height", height);
17.37 + }
17.38 +
17.39 + public int getHeight() {
17.40 + return (Integer) getAttribute(this, "height");
17.41 + }
17.42 +
17.43 + public void setWidth(int width) {
17.44 + setAttribute(this, "width", width);
17.45 + }
17.46 +
17.47 + public int getWidth() {
17.48 + return (Integer) getAttribute(this, "width");
17.49 + }
17.50 +
17.51 + @JavaScriptBody(
17.52 + args = {"el"},
17.53 + body = "var e = window.document.getElementById(el.fld_id);\n"
17.54 + + "return e.getContext('2d');\n")
17.55 + private native static Object getContextImpl(Canvas el);
17.56 +
17.57 + public GraphicsContext getContext() {
17.58 + return new GraphicsContext(getContextImpl(this));
17.59 + }
17.60 +
17.61 + @Override
17.62 + void dontSubclass() {
17.63 + }
17.64 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ComputedProperty.java Wed Jan 23 12:53:23 2013 +0100
18.3 @@ -0,0 +1,38 @@
18.4 +/**
18.5 + * Back 2 Browser Bytecode Translator
18.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
18.7 + *
18.8 + * This program is free software: you can redistribute it and/or modify
18.9 + * it under the terms of the GNU General Public License as published by
18.10 + * the Free Software Foundation, version 2 of the License.
18.11 + *
18.12 + * This program is distributed in the hope that it will be useful,
18.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
18.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18.15 + * GNU General Public License for more details.
18.16 + *
18.17 + * You should have received a copy of the GNU General Public License
18.18 + * along with this program. Look for COPYING file in the top folder.
18.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
18.20 + */
18.21 +package org.apidesign.bck2brwsr.htmlpage.api;
18.22 +
18.23 +import java.lang.annotation.ElementType;
18.24 +import java.lang.annotation.Retention;
18.25 +import java.lang.annotation.RetentionPolicy;
18.26 +import java.lang.annotation.Target;
18.27 +
18.28 +/** Can be used in classes annotated with {@link Page} annotation to
18.29 + * define a derived property. Value of derived property is based on values
18.30 + * of {@link Property} as enumerated by {@link Page#properties()}.
18.31 + * <p>
18.32 + * The name of the derived property is the name of the method. The arguments
18.33 + * of the method define the property names (from {@link Page#properties()} list)
18.34 + * the value of property depends on.
18.35 + *
18.36 + * @author Jaroslav Tulach <jtulach@netbeans.org>
18.37 + */
18.38 +@Retention(RetentionPolicy.SOURCE)
18.39 +@Target(ElementType.METHOD)
18.40 +public @interface ComputedProperty {
18.41 +}
19.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Tue Jan 22 19:48:10 2013 +0100
19.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Element.java Wed Jan 23 12:53:23 2013 +0100
19.3 @@ -30,6 +30,13 @@
19.4 this.id = id;
19.5 }
19.6
19.7 + /** Id of the element in the document.
19.8 + * @return the id for this element
19.9 + */
19.10 + public String getId() {
19.11 + return id;
19.12 + }
19.13 +
19.14 abstract void dontSubclass();
19.15
19.16 @JavaScriptBody(
19.17 @@ -46,6 +53,12 @@
19.18 )
19.19 static native Object getAttribute(Element el, String property);
19.20
19.21 + @JavaScriptBody(
19.22 + args={"el"},
19.23 + body="return window.document.getElementById(el.fld_id);"
19.24 + )
19.25 + static native Object getElementById(Element el);
19.26 +
19.27 /** Executes given runnable when user performs a "click" on the given
19.28 * element.
19.29 * @param r the runnable to execute, never null
19.30 @@ -55,7 +68,8 @@
19.31 body="var e = window.document.getElementById(this.fld_id);\n"
19.32 + "e[ev.fld_id] = function() { r.run__V(); };\n"
19.33 )
19.34 - final native void on(OnEvent ev, Runnable r);
19.35 + final void on(OnEvent ev, Runnable r) {
19.36 + }
19.37
19.38 /** Shows alert message dialog in a browser.
19.39 * @param msg the message to show
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/GraphicsContext.java Wed Jan 23 12:53:23 2013 +0100
20.3 @@ -0,0 +1,335 @@
20.4 +/**
20.5 + * Back 2 Browser Bytecode Translator
20.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
20.7 + *
20.8 + * This program is free software: you can redistribute it and/or modify
20.9 + * it under the terms of the GNU General Public License as published by
20.10 + * the Free Software Foundation, version 2 of the License.
20.11 + *
20.12 + * This program is distributed in the hope that it will be useful,
20.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
20.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20.15 + * GNU General Public License for more details.
20.16 + *
20.17 + * You should have received a copy of the GNU General Public License
20.18 + * along with this program. Look for COPYING file in the top folder.
20.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
20.20 + */
20.21 +package org.apidesign.bck2brwsr.htmlpage.api;
20.22 +
20.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
20.24 +
20.25 +/**
20.26 + *
20.27 + * @author Anton Epple <toni.epple@eppleton.de>
20.28 + */
20.29 +public class GraphicsContext {
20.30 +
20.31 + Object context;
20.32 +
20.33 + GraphicsContext(Object contextImpl) {
20.34 + this.context = contextImpl;
20.35 + }
20.36 +
20.37 + @JavaScriptBody(args = {"centerx", "centery", "radius", "startangle", "endangle", "ccw"},
20.38 + body = "this.fld_context.arc(centerx,centery, radius, startangle, endangle,ccw);")
20.39 + public native void arc(double centerX,
20.40 + double centerY,
20.41 + double startAngle,
20.42 + double radius,
20.43 + double endAngle,
20.44 + boolean ccw);
20.45 +
20.46 + @JavaScriptBody(args = {"x1", "y1", "x2", "y2", "r"},
20.47 + body = "this.fld_context.arcTo(x1,y1,x2,y2,r);")
20.48 + public native void arcTo(double x1,
20.49 + double y1,
20.50 + double x2,
20.51 + double y2,
20.52 + double r);
20.53 +
20.54 + @JavaScriptBody(args = {"x", "y"},
20.55 + body = "return this.fld_context.isPointInPath(x,y);")
20.56 + public native boolean isPointInPath(double x, double y);
20.57 +
20.58 + @JavaScriptBody(args = {}, body = "this.fld_context.fill();")
20.59 + public native void fill();
20.60 +
20.61 + @JavaScriptBody(args = {}, body = "this.fld_context.stroke();")
20.62 + public native void stroke();
20.63 +
20.64 + @JavaScriptBody(args = {}, body = "this.fld_context.beginPath();")
20.65 + public native void beginPath();
20.66 +
20.67 + @JavaScriptBody(args = {}, body = "this.fld_context.closePath();")
20.68 + public native void closePath();
20.69 +
20.70 + @JavaScriptBody(args = {}, body = "this.fld_context.clip();")
20.71 + public native void clip();
20.72 +
20.73 + @JavaScriptBody(args = {"x", "y"}, body = "this.fld_context.moveTo(x,y);")
20.74 + public native void moveTo(double x, double y);
20.75 +
20.76 + @JavaScriptBody(args = {"x", "y"}, body = "this.fld_context.lineTo(x,y);")
20.77 + public native void lineTo(double x, double y);
20.78 +
20.79 + @JavaScriptBody(args = {"cpx", "cpy", "x", "y"}, body = "this.fld_context.quadraticCurveTo(cpx,cpy,x,y);")
20.80 + public native void quadraticCurveTo(double cpx, double cpy, double x, double y);
20.81 +
20.82 + @JavaScriptBody(args = {"cp1x", "cp1y", "cp2x", "cp2y", "x", "y"},
20.83 + body = "this.fld_context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);")
20.84 + public native void bezierCurveTo(double cp1x, double cp1y, double cp2x, double cp2y, double x, double y);
20.85 +
20.86 + @JavaScriptBody(args = {"x", "y", "width", "height"}, body = "this.fld_context.fillRect(x,y,width,height);")
20.87 + public native void fillRect(double x, double y, double width, double height);
20.88 +
20.89 + @JavaScriptBody(args = {"x", "y", "width", "height"}, body = "this.fld_context.strokeRect(x,y,width,height);")
20.90 + public native void strokeRect(double x, double y, double width, double height);
20.91 +
20.92 + @JavaScriptBody(args = {"x", "y", "width", "height"}, body = "this.fld_context.clearRect(x,y,width,height);")
20.93 + public native void clearRect(double x, double y, double width, double height);
20.94 +
20.95 + @JavaScriptBody(args = {"x", "y", "width", "height"}, body = "this.fld_context.rectect(x,y,width,height);")
20.96 + public native void rect(double x, double y, double width, double height);
20.97 +
20.98 + @JavaScriptBody(args = {}, body = "this.fld_context.save();")
20.99 + public native void save();
20.100 +
20.101 + @JavaScriptBody(args = {}, body = "this.fld_context.restore();")
20.102 + public native void restore();
20.103 +
20.104 + @JavaScriptBody(args = {"angle"}, body = "this.fld_context.rotate(angle);")
20.105 + public native void rotate(double angle);
20.106 +
20.107 + @JavaScriptBody(args = {"a", "b", "c", "d", "e", "f"}, body = "this.fld_context.transform(a,b,c,d,e,f);")
20.108 + public native void transform(double a, double b, double c, double d, double e, double f);
20.109 +
20.110 + @JavaScriptBody(args = {"a", "b", "c", "d", "e", "f"}, body = "this.fld_context.setTransform(a,b,c,d,e,f);")
20.111 + public native void setTransform(double a, double b, double c, double d, double e, double f);
20.112 +
20.113 + @JavaScriptBody(args = {"x", "y"}, body = "this.fld_context.translate(x,y);")
20.114 + public native void translate(double x, double y);
20.115 +
20.116 + @JavaScriptBody(args = {"x", "y"}, body = "this.fld_context.scale(x,y);")
20.117 + public native void scale(double x, double y);
20.118 +
20.119 + public void drawImage(Image image, double x, double y) {
20.120 + drawImageImpl(context, Element.getElementById(image), x, y);
20.121 + }
20.122 +
20.123 + public void drawImage(Image image, double x, double y, double width, double height) {
20.124 + drawImageImpl(context, Element.getElementById(image), x, y, width, height);
20.125 + }
20.126 +
20.127 + public void drawImage(Image image, double sx, double sy, double sWidth, double sHeight, double x, double y, double width, double height) {
20.128 + drawImageImpl(context, Element.getElementById(image), sx, sy, sWidth, sHeight, x, y, width, height);
20.129 + }
20.130 +
20.131 + @JavaScriptBody(args = {"ctx", "img", "x", "y", "width", "height"}, body = "ctx.drawImage(img,x,y,width,height);")
20.132 + private native static void drawImageImpl(Object ctx, Object img, double x, double y, double width, double height);
20.133 +
20.134 + @JavaScriptBody(args = {"ctx", "img", "sx", "sy", "swidth", "sheight", "x", "y", "width", "height"}, body = "ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);")
20.135 + private native static void drawImageImpl(Object ctx, Object img, double sx, double sy, double sWidth, double sHeight, double x, double y, double width, double height);
20.136 +
20.137 + @JavaScriptBody(args = {"ctx", "img", "x", "y"}, body = "ctx.drawImage(img,x,y);")
20.138 + private native static void drawImageImpl(Object ctx, Object img, double x, double y);
20.139 +
20.140 + @JavaScriptBody(args = {"style"}, body = "this.fld_context.fillStyle=style;")
20.141 + public native void setFillStyle(String style);
20.142 +
20.143 + @JavaScriptBody(args = {}, body = "return this.fld_context.fillStyle;")
20.144 + public native String getFillStyle();
20.145 +
20.146 + public void setFillStyle(LinearGradient style) {
20.147 + setFillStyleImpl(context, style.object());
20.148 + }
20.149 +
20.150 + public void setFillStyle(RadialGradient style) {
20.151 + setFillStyleImpl(context, style.object());
20.152 + }
20.153 +
20.154 + public void setFillStyle(Pattern style) {
20.155 + setFillStyleImpl(context, style.object());
20.156 + }
20.157 +
20.158 + @JavaScriptBody(args = {"context","obj"}, body = "context.fillStyle=obj;")
20.159 + private native void setFillStyleImpl(Object context, Object obj);
20.160 +
20.161 + @JavaScriptBody(args = {"style"}, body = "this.fld_context.strokeStyle=style;")
20.162 + public native void setStrokeStyle(String style);
20.163 +
20.164 + public void setStrokeStyle(LinearGradient style) {
20.165 + setStrokeStyleImpl(context, style.object());
20.166 + }
20.167 +
20.168 + public void setStrokeStyle(RadialGradient style) {
20.169 + setStrokeStyleImpl(context, style.object());
20.170 + }
20.171 +
20.172 + @JavaScriptBody(args = {"style"}, body = "this.fld_context.fillStyle=style;")
20.173 + public void setStrokeStyle(Pattern style) {
20.174 + setStrokeStyleImpl(context, style.object());
20.175 + }
20.176 +
20.177 + @JavaScriptBody(args = {"context","obj"}, body = "context.strokeStyle=obj;")
20.178 + private native void setStrokeStyleImpl(Object context, Object obj);
20.179 +
20.180 + @JavaScriptBody(args = {"color"}, body = "this.fld_context.shadowColor=color;")
20.181 + public native void setShadowColor(String color);
20.182 +
20.183 + @JavaScriptBody(args = {"blur"}, body = "this.fld_context.shadowBlur=blur;")
20.184 + public native void setShadowBlur(double blur);
20.185 +
20.186 + @JavaScriptBody(args = {"x"}, body = "this.fld_context.shadowOffsetX=x;")
20.187 + public native void setShadowOffsetX(double x);
20.188 +
20.189 + @JavaScriptBody(args = {"y"}, body = "this.fld_context.shadowOffsetY=y;")
20.190 + public native void setShadowOffsetY(double y);
20.191 +
20.192 + @JavaScriptBody(args = {}, body = "return this.fld_context.strokeStyle;")
20.193 + public native String getStrokeStyle();
20.194 +
20.195 + @JavaScriptBody(args = {}, body = "return this.fld_context.shadowColor;")
20.196 + public native String getShadowColor();
20.197 +
20.198 + @JavaScriptBody(args = {}, body = "return this.fld_context.shadowBlur;")
20.199 + public native double getShadowBlur();
20.200 +
20.201 + @JavaScriptBody(args = {}, body = "return this.fld_context.shadowOffsetX;")
20.202 + public native double getShadowOffsetX();
20.203 +
20.204 + @JavaScriptBody(args = {}, body = "return this.fld_context.shadowOffsetY;")
20.205 + public native double getShadowOffsetY();
20.206 +
20.207 + @JavaScriptBody(args = {}, body = "return this.fld_context.lineCap;")
20.208 + public native String getLineCap();
20.209 +
20.210 + @JavaScriptBody(args = {"style"}, body = "this.fld_context.lineCap=style;")
20.211 + public native void setLineCap(String style);
20.212 +
20.213 + @JavaScriptBody(args = {}, body = "return this.fld_context.lineJoin;")
20.214 + public native String getLineJoin();
20.215 +
20.216 + @JavaScriptBody(args = {"style"}, body = "this.fld_context.lineJoin=style;")
20.217 + public native void setLineJoin(String style) ;
20.218 +
20.219 + @JavaScriptBody(args = {}, body = "return this.fld_context.lineWidth;")
20.220 + public native double getLineWidth();
20.221 +
20.222 + @JavaScriptBody(args = {"width"}, body = "this.fld_context.lineJoin=width;")
20.223 + public native void setLineWidth(double width);
20.224 +
20.225 + @JavaScriptBody(args = {}, body = "return this.fld_context.miterLimit;")
20.226 + public native double getMiterLimit();
20.227 +
20.228 + @JavaScriptBody(args = {"limit"}, body = "this.fld_context.miterLimit=limit;")
20.229 + public native void setMiterLimit(double limit);
20.230 +
20.231 + @JavaScriptBody(args = {}, body = "return this.fld_context.font;")
20.232 + public native String getFont();
20.233 +
20.234 + @JavaScriptBody(args = {"font"}, body = "this.fld_context.font=font;")
20.235 + public native void setFont(String font);
20.236 +
20.237 + @JavaScriptBody(args = {}, body = "return this.fld_context.textAlign;")
20.238 + public native String getTextAlign();
20.239 +
20.240 + @JavaScriptBody(args = {"textalign"}, body = "this.fld_context.textAlign=textalign;")
20.241 + public native void setTextAlign(String textAlign);
20.242 +
20.243 + @JavaScriptBody(args = {}, body = "return this.fld_context.textBaseline;")
20.244 + public native String getTextBaseline();
20.245 +
20.246 + @JavaScriptBody(args = {"textbaseline"}, body = "this.fld_context.textBaseline=textbaseline;")
20.247 + public native void setTextBaseline(String textbaseline);
20.248 +
20.249 + @JavaScriptBody(args = {"text", "x", "y"}, body = "this.fld_context.fillText(text,x,y);")
20.250 + public native void fillText(String text, double x, double y);
20.251 +
20.252 + @JavaScriptBody(args = {"text", "x", "y", "maxwidth"}, body = "this.fld_context.fillText(text,x,y,maxwidth);")
20.253 + public void fillText(String text, double x, double y, double maxWidth) {
20.254 + }
20.255 +
20.256 + public TextMetrics measureText(String text) {
20.257 + return new TextMetrics(measureTextImpl(text));
20.258 + }
20.259 +
20.260 + @JavaScriptBody(args = {"text"},
20.261 + body = "return this.fld_context.measureText(text);")
20.262 + private native Object measureTextImpl(String text);
20.263 +
20.264 + @JavaScriptBody(args = {"text", "x", "y"}, body = "this.fld_context.strokeText(text,x,y);")
20.265 + public native void strokeText(String text, double x, double y);
20.266 +
20.267 + @JavaScriptBody(args = {"text", "x", "y", "maxWidth"}, body = "this.fld_context.strokeText(text,x,y,maxWidth);")
20.268 + public native void strokeText(String text, double x, double y, double maxWidth) ;
20.269 +
20.270 + public ImageData createImageData(double x, double y) {
20.271 + return new ImageData(createImageDataImpl(x, y));
20.272 + }
20.273 +
20.274 + @JavaScriptBody(args = {"x", "y"},
20.275 + body = "return this.fld_context.createImageData(x,y);")
20.276 + private native Object createImageDataImpl(double x, double y);
20.277 +
20.278 + public ImageData createImageData(ImageData imageData) {
20.279 + return new ImageData(createImageDataImpl(imageData.getWidth(), imageData.getHeight()));
20.280 + }
20.281 +
20.282 + public ImageData getImageData(double x, double y, double width, double height) {
20.283 + return new ImageData(getImageDataImpl(x, y, width, height));
20.284 + }
20.285 +
20.286 + @JavaScriptBody(args = {"x", "y", "width", "height"},
20.287 + body = "return this.fld_context.getImageData(x,y,width,height);")
20.288 + private native Object getImageDataImpl(double x, double y, double width, double height);
20.289 +
20.290 + public void putImageData(ImageData imageData, double x, double y) {
20.291 + putImageDataImpl(imageData.object(), x, y);
20.292 + }
20.293 +
20.294 + @JavaScriptBody(args = {"imageData", "x", "y"},
20.295 + body = "this.fld_context.putImageData(imageData,x,y);")
20.296 + private native void putImageDataImpl(Object imageData, double x, double y);
20.297 +
20.298 + public void putImageData(ImageData imageData, double x, double y, double dirtyx, double dirtyy, double dirtywidth, double dirtyheight) {
20.299 + putImageDataImpl(imageData.object(), x, y, dirtyx, dirtyy, dirtywidth, dirtyheight);
20.300 + }
20.301 +
20.302 + @JavaScriptBody(args = {"imageData", "x", "y", "dirtyx", "dirtyy", "dirtywidth", "dirtyheight"},
20.303 + body = "this.fld_context.putImageData(imageData,x,y, dirtyx, dirtyy, dirtywidth,dirtyheight);")
20.304 + private native void putImageDataImpl(Object imageData, double x, double y, double dirtyx, double dirtyy, double dirtywidth, double dirtyheight);
20.305 +
20.306 + @JavaScriptBody(args = {"alpha"}, body = "this.fld_context.globalAlpha=alpha;")
20.307 + public native void setGlobalAlpha(double alpha) ;
20.308 +
20.309 + @JavaScriptBody(args = {}, body = "return this.fld_context.globalAlpha;")
20.310 + public native double getGlobalAlpha();
20.311 +
20.312 + @JavaScriptBody(args = {"operation"}, body = "this.fld_context.globalCompositeOperation=operation;")
20.313 + public native void setGlobalCompositeOperation(double alpha);
20.314 +
20.315 + @JavaScriptBody(args = {}, body = "return this.fld_context.globalCompositeOperation;")
20.316 + public native double getGlobalCompositeOperation();
20.317 +
20.318 + public LinearGradient createLinearGradient(double x0, double y0, double x1, double y1) {
20.319 + return new LinearGradient(createLinearGradientImpl(context, x0, y0, x1, y1));
20.320 + }
20.321 +
20.322 + @JavaScriptBody(args = {"context", "x0", "y0", "x1", "y1"}, body = "return context.createLinearGradient(x0,y0,x1,y1);")
20.323 + private native Object createLinearGradientImpl(Object context, double x0, double y0, double x1, double y1);
20.324 +
20.325 + public Pattern createPattern(Image image, String repeat) {
20.326 + return new Pattern(createPatternImpl(context, image, repeat));
20.327 + }
20.328 +
20.329 + @JavaScriptBody(args = {"context", "image", "repeat"}, body = "return context.createPattern(image, repeat);")
20.330 + private static native Object createPatternImpl(Object context, Image image, String repeat);
20.331 +
20.332 + public RadialGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1) {
20.333 + return new RadialGradient(createRadialGradientImpl(context, x0, y0, r0, x1, y1, r1));
20.334 + }
20.335 +
20.336 + @JavaScriptBody(args = {"context", "x0", "y0", "r0", "x1", "y1", "r1"}, body = "return context.createRadialGradient(x0,y0,r0,x1,y1,r1);")
20.337 + private static native Object createRadialGradientImpl(Object context, double x0, double y0, double r0, double x1, double y1, double r1);
20.338 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Image.java Wed Jan 23 12:53:23 2013 +0100
21.3 @@ -0,0 +1,36 @@
21.4 +/**
21.5 + * Back 2 Browser Bytecode Translator
21.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
21.7 + *
21.8 + * This program is free software: you can redistribute it and/or modify
21.9 + * it under the terms of the GNU General Public License as published by
21.10 + * the Free Software Foundation, version 2 of the License.
21.11 + *
21.12 + * This program is distributed in the hope that it will be useful,
21.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
21.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21.15 + * GNU General Public License for more details.
21.16 + *
21.17 + * You should have received a copy of the GNU General Public License
21.18 + * along with this program. Look for COPYING file in the top folder.
21.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
21.20 + */
21.21 +package org.apidesign.bck2brwsr.htmlpage.api;
21.22 +
21.23 +/**
21.24 + *
21.25 + * @author Anton Epple <toni.epple@eppleton.de>
21.26 + */
21.27 +public class Image extends Element{
21.28 +
21.29 + public Image(String id) {
21.30 + super(id);
21.31 + }
21.32 +
21.33 +
21.34 +
21.35 + @Override
21.36 + void dontSubclass() {
21.37 + }
21.38 +
21.39 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/ImageData.java Wed Jan 23 12:53:23 2013 +0100
22.3 @@ -0,0 +1,89 @@
22.4 +/**
22.5 + * Back 2 Browser Bytecode Translator
22.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
22.7 + *
22.8 + * This program is free software: you can redistribute it and/or modify
22.9 + * it under the terms of the GNU General Public License as published by
22.10 + * the Free Software Foundation, version 2 of the License.
22.11 + *
22.12 + * This program is distributed in the hope that it will be useful,
22.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
22.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22.15 + * GNU General Public License for more details.
22.16 + *
22.17 + * You should have received a copy of the GNU General Public License
22.18 + * along with this program. Look for COPYING file in the top folder.
22.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
22.20 + */
22.21 +/*
22.22 + * To change this template, choose Tools | Templates
22.23 + * and open the template in the editor.
22.24 + */
22.25 +package org.apidesign.bck2brwsr.htmlpage.api;
22.26 +
22.27 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
22.28 +
22.29 +/**
22.30 + *
22.31 + * @author Anton Epple <toni.epple@eppleton.de>
22.32 + */
22.33 +public class ImageData {
22.34 +
22.35 + private Object imageData;
22.36 + private Data data;
22.37 +
22.38 + public ImageData(Object imageData) {
22.39 + this.imageData = imageData;
22.40 + }
22.41 +
22.42 + public Data getData(){
22.43 + if (data == null){
22.44 + data = new Data(getDataImpl(imageData));
22.45 + }
22.46 + return data;
22.47 + }
22.48 +
22.49 + @JavaScriptBody(args = {"imageData"}, body = "return imageData.data")
22.50 + public native Object getDataImpl(Object imageData);
22.51 +
22.52 + public double getWidth() {
22.53 + return getWidthImpl(imageData);
22.54 + }
22.55 +
22.56 + @JavaScriptBody(args = {"imageData"}, body = "return imagedata.width;")
22.57 + private static native double getWidthImpl(Object imageData);
22.58 +
22.59 + public double getHeight() {
22.60 + return getHeightImpl(imageData);
22.61 + }
22.62 +
22.63 + @JavaScriptBody(args = {"imageData"}, body = "return imagedata.height;")
22.64 + private static native double getHeightImpl(Object imageData);
22.65 +
22.66 + Object object() {
22.67 + return imageData;
22.68 + }
22.69 +
22.70 + public static class Data {
22.71 +
22.72 + Object data;
22.73 +
22.74 + public Data(Object data) {
22.75 + this.data = data;
22.76 + }
22.77 +
22.78 + public int get(int index) {
22.79 + return getImpl(data, index);
22.80 + }
22.81 +
22.82 + public void set(int index, int value) {
22.83 + setImpl(data, index, value);
22.84 + }
22.85 +
22.86 + @JavaScriptBody(args = {"data", "index", "value"}, body = "data[index]=value;")
22.87 + private static native void setImpl(Object data, int index, int value);
22.88 +
22.89 + @JavaScriptBody(args = {"imagedata", "index"}, body = "return data[index];")
22.90 + private static native int getImpl(Object data, int index);
22.91 + }
22.92 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/LinearGradient.java Wed Jan 23 12:53:23 2013 +0100
23.3 @@ -0,0 +1,45 @@
23.4 +/**
23.5 + * Back 2 Browser Bytecode Translator
23.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
23.7 + *
23.8 + * This program is free software: you can redistribute it and/or modify
23.9 + * it under the terms of the GNU General Public License as published by
23.10 + * the Free Software Foundation, version 2 of the License.
23.11 + *
23.12 + * This program is distributed in the hope that it will be useful,
23.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
23.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23.15 + * GNU General Public License for more details.
23.16 + *
23.17 + * You should have received a copy of the GNU General Public License
23.18 + * along with this program. Look for COPYING file in the top folder.
23.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
23.20 + */
23.21 +package org.apidesign.bck2brwsr.htmlpage.api;
23.22 +
23.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
23.24 +
23.25 +/**
23.26 + *
23.27 + * @author Anton Epple <toni.epple@eppleton.de>
23.28 + */
23.29 +public class LinearGradient {
23.30 +
23.31 + private final Object gradient;
23.32 +
23.33 + LinearGradient(Object linearGradient) {
23.34 + this.gradient = linearGradient;
23.35 + }
23.36 +
23.37 + Object object() {
23.38 + return gradient;
23.39 + }
23.40 +
23.41 + public void addColorStop(double position, String color) {
23.42 + addColorStopImpl(gradient, position, color);
23.43 + }
23.44 +
23.45 + @JavaScriptBody(args = {"gradient", "position", "color"}, body =
23.46 + "gradient.addColorStop(position,color)")
23.47 + private static native void addColorStopImpl(Object gradient, double position, String color);
23.48 +}
24.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnEvent.java Tue Jan 22 19:48:10 2013 +0100
24.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/OnEvent.java Wed Jan 23 12:53:23 2013 +0100
24.3 @@ -26,6 +26,7 @@
24.4 BLUR("onblur"),
24.5 CAN_PLAY("oncanplay"),
24.6 CAN_PLAY_THROUGH("oncanplaythrough"),
24.7 + CHANGE("onchange"),
24.8 CLICK("onclick"),
24.9 CONTEXT_MENU("oncontextmenu"),
24.10 DBL_CLICK("ondblclick"),
24.11 @@ -82,6 +83,13 @@
24.12 this.id = id;
24.13 }
24.14
24.15 + /** The name of property this event is referenced by from an {@link Element}.
24.16 + * For {@link OnEvent#CHANGE}, it is <code>onchange</code>.
24.17 + */
24.18 + public String getElementPropertyName() {
24.19 + return id;
24.20 + }
24.21 +
24.22 /** What should happen when this even happen on one
24.23 * of associated elements. Continue by calling {@link OnController#perform(java.lang.Runnable)}
24.24 * method.
25.1 --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Page.java Tue Jan 22 19:48:10 2013 +0100
25.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Page.java Wed Jan 23 12:53:23 2013 +0100
25.3 @@ -36,4 +36,7 @@
25.4 * found elements with IDs.
25.5 */
25.6 String className() default "";
25.7 + /** List of properties generated into the page.
25.8 + */
25.9 + Property[] properties() default {};
25.10 }
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Paint.java Wed Jan 23 12:53:23 2013 +0100
26.3 @@ -0,0 +1,30 @@
26.4 +/**
26.5 + * Back 2 Browser Bytecode Translator
26.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
26.7 + *
26.8 + * This program is free software: you can redistribute it and/or modify
26.9 + * it under the terms of the GNU General Public License as published by
26.10 + * the Free Software Foundation, version 2 of the License.
26.11 + *
26.12 + * This program is distributed in the hope that it will be useful,
26.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
26.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26.15 + * GNU General Public License for more details.
26.16 + *
26.17 + * You should have received a copy of the GNU General Public License
26.18 + * along with this program. Look for COPYING file in the top folder.
26.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
26.20 + */
26.21 +package org.apidesign.bck2brwsr.htmlpage.api;
26.22 +
26.23 +/**
26.24 + *
26.25 + * @author Anton Epple <toni.epple@eppleton.de>
26.26 + */
26.27 +public class Paint {
26.28 +
26.29 +
26.30 + String asString(){
26.31 + return "";
26.32 + }
26.33 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Pattern.java Wed Jan 23 12:53:23 2013 +0100
27.3 @@ -0,0 +1,35 @@
27.4 +/**
27.5 + * Back 2 Browser Bytecode Translator
27.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
27.7 + *
27.8 + * This program is free software: you can redistribute it and/or modify
27.9 + * it under the terms of the GNU General Public License as published by
27.10 + * the Free Software Foundation, version 2 of the License.
27.11 + *
27.12 + * This program is distributed in the hope that it will be useful,
27.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
27.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27.15 + * GNU General Public License for more details.
27.16 + *
27.17 + * You should have received a copy of the GNU General Public License
27.18 + * along with this program. Look for COPYING file in the top folder.
27.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
27.20 + */
27.21 +package org.apidesign.bck2brwsr.htmlpage.api;
27.22 +
27.23 +/**
27.24 + *
27.25 + * @author Anton Epple <toni.epple@eppleton.de>
27.26 + */
27.27 +public class Pattern {
27.28 +
27.29 + private Object pattern;
27.30 +
27.31 + public Pattern(Object pattern) {
27.32 + this.pattern = pattern;
27.33 + }
27.34 +
27.35 + Object object() {
27.36 + return pattern;
27.37 + }
27.38 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/Property.java Wed Jan 23 12:53:23 2013 +0100
28.3 @@ -0,0 +1,34 @@
28.4 +/**
28.5 + * Back 2 Browser Bytecode Translator
28.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
28.7 + *
28.8 + * This program is free software: you can redistribute it and/or modify
28.9 + * it under the terms of the GNU General Public License as published by
28.10 + * the Free Software Foundation, version 2 of the License.
28.11 + *
28.12 + * This program is distributed in the hope that it will be useful,
28.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
28.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28.15 + * GNU General Public License for more details.
28.16 + *
28.17 + * You should have received a copy of the GNU General Public License
28.18 + * along with this program. Look for COPYING file in the top folder.
28.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
28.20 + */
28.21 +package org.apidesign.bck2brwsr.htmlpage.api;
28.22 +
28.23 +import java.lang.annotation.Retention;
28.24 +import java.lang.annotation.RetentionPolicy;
28.25 +import java.lang.annotation.Target;
28.26 +
28.27 +/** Represents a property in a generated model of an HTML
28.28 + * {@link Page}.
28.29 + *
28.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
28.31 + */
28.32 +@Retention(RetentionPolicy.SOURCE)
28.33 +@Target({})
28.34 +public @interface Property {
28.35 + String name();
28.36 + Class<?> type();
28.37 +}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/RadialGradient.java Wed Jan 23 12:53:23 2013 +0100
29.3 @@ -0,0 +1,45 @@
29.4 +/**
29.5 + * Back 2 Browser Bytecode Translator
29.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
29.7 + *
29.8 + * This program is free software: you can redistribute it and/or modify
29.9 + * it under the terms of the GNU General Public License as published by
29.10 + * the Free Software Foundation, version 2 of the License.
29.11 + *
29.12 + * This program is distributed in the hope that it will be useful,
29.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
29.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29.15 + * GNU General Public License for more details.
29.16 + *
29.17 + * You should have received a copy of the GNU General Public License
29.18 + * along with this program. Look for COPYING file in the top folder.
29.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
29.20 + */
29.21 +package org.apidesign.bck2brwsr.htmlpage.api;
29.22 +
29.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
29.24 +
29.25 +/**
29.26 + *
29.27 + * @author Anton Epple <toni.epple@eppleton.de>
29.28 + */
29.29 +public class RadialGradient {
29.30 +
29.31 + private Object gradient;
29.32 +
29.33 + public RadialGradient(Object radialGradient) {
29.34 + this.gradient = radialGradient;
29.35 + }
29.36 +
29.37 + public void addColorStop(double position, String color) {
29.38 + addColorStopImpl(gradient, position, color);
29.39 + }
29.40 +
29.41 + @JavaScriptBody(args = {"gradient", "position", "color"}, body =
29.42 + "gradient.addColorStop(position,color)")
29.43 + private static native void addColorStopImpl(Object gradient, double position, String color);
29.44 +
29.45 + Object object() {
29.46 + return gradient;
29.47 + }
29.48 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/api/TextMetrics.java Wed Jan 23 12:53:23 2013 +0100
30.3 @@ -0,0 +1,48 @@
30.4 +/**
30.5 + * Back 2 Browser Bytecode Translator
30.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
30.7 + *
30.8 + * This program is free software: you can redistribute it and/or modify
30.9 + * it under the terms of the GNU General Public License as published by
30.10 + * the Free Software Foundation, version 2 of the License.
30.11 + *
30.12 + * This program is distributed in the hope that it will be useful,
30.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
30.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30.15 + * GNU General Public License for more details.
30.16 + *
30.17 + * You should have received a copy of the GNU General Public License
30.18 + * along with this program. Look for COPYING file in the top folder.
30.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
30.20 + */
30.21 +package org.apidesign.bck2brwsr.htmlpage.api;
30.22 +
30.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
30.24 +
30.25 +/**
30.26 + *
30.27 + * @author Anton Epple <toni.epple@eppleton.de>
30.28 + */
30.29 +public class TextMetrics {
30.30 +
30.31 + private Object textMetrics;
30.32 +
30.33 + TextMetrics(Object measureTextImpl) {
30.34 + this.textMetrics = measureTextImpl;
30.35 + }
30.36 +
30.37 + @JavaScriptBody(args = {"textMetrics"}, body = "return textMetrics.width;")
30.38 + private native double getWidth(Object textMetrics);
30.39 +
30.40 + @JavaScriptBody(args = {"textMetrics"}, body = "return textMetrics.height;")
30.41 + private native double getHeight(Object textMetrics);
30.42 +
30.43 + public double getWidth() {
30.44 + return getWidth(textMetrics);
30.45 + }
30.46 +
30.47 + public double getHeight() {
30.48 + return getHeight(textMetrics);
30.49 +
30.50 + }
30.51 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout-2.2.1.js Wed Jan 23 12:53:23 2013 +0100
31.3 @@ -0,0 +1,3587 @@
31.4 +// Knockout JavaScript library v2.2.1
31.5 +// (c) Steven Sanderson - http://knockoutjs.com/
31.6 +// License: MIT (http://www.opensource.org/licenses/mit-license.php)
31.7 +
31.8 +(function(){
31.9 +var DEBUG=true;
31.10 +(function(window,document,navigator,jQuery,undefined){
31.11 +!function(factory) {
31.12 + // Support three module loading scenarios
31.13 + if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
31.14 + // [1] CommonJS/Node.js
31.15 + var target = module['exports'] || exports; // module.exports is for Node.js
31.16 + factory(target);
31.17 + } else if (typeof define === 'function' && define['amd']) {
31.18 + // [2] AMD anonymous module
31.19 + define(['exports'], factory);
31.20 + } else {
31.21 + // [3] No module loader (plain <script> tag) - put directly in global namespace
31.22 + factory(window['ko'] = {});
31.23 + }
31.24 +}(function(koExports){
31.25 +// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
31.26 +// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
31.27 +var ko = typeof koExports !== 'undefined' ? koExports : {};
31.28 +// Google Closure Compiler helpers (used only to make the minified file smaller)
31.29 +ko.exportSymbol = function(koPath, object) {
31.30 + var tokens = koPath.split(".");
31.31 +
31.32 + // In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
31.33 + // At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
31.34 + var target = ko;
31.35 +
31.36 + for (var i = 0; i < tokens.length - 1; i++)
31.37 + target = target[tokens[i]];
31.38 + target[tokens[tokens.length - 1]] = object;
31.39 +};
31.40 +ko.exportProperty = function(owner, publicName, object) {
31.41 + owner[publicName] = object;
31.42 +};
31.43 +ko.version = "2.2.1";
31.44 +
31.45 +ko.exportSymbol('version', ko.version);
31.46 +ko.utils = new (function () {
31.47 + var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
31.48 +
31.49 + // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
31.50 + var knownEvents = {}, knownEventTypesByEventName = {};
31.51 + var keyEventTypeName = /Firefox\/2/i.test(navigator.userAgent) ? 'KeyboardEvent' : 'UIEvents';
31.52 + knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
31.53 + knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
31.54 + for (var eventType in knownEvents) {
31.55 + var knownEventsForType = knownEvents[eventType];
31.56 + if (knownEventsForType.length) {
31.57 + for (var i = 0, j = knownEventsForType.length; i < j; i++)
31.58 + knownEventTypesByEventName[knownEventsForType[i]] = eventType;
31.59 + }
31.60 + }
31.61 + var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
31.62 +
31.63 + // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
31.64 + // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
31.65 + // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
31.66 + // If there is a future need to detect specific versions of IE10+, we will amend this.
31.67 + var ieVersion = (function() {
31.68 + var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
31.69 +
31.70 + // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
31.71 + while (
31.72 + div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
31.73 + iElems[0]
31.74 + );
31.75 + return version > 4 ? version : undefined;
31.76 + }());
31.77 + var isIe6 = ieVersion === 6,
31.78 + isIe7 = ieVersion === 7;
31.79 +
31.80 + function isClickOnCheckableElement(element, eventType) {
31.81 + if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
31.82 + if (eventType.toLowerCase() != "click") return false;
31.83 + var inputType = element.type;
31.84 + return (inputType == "checkbox") || (inputType == "radio");
31.85 + }
31.86 +
31.87 + return {
31.88 + fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
31.89 +
31.90 + arrayForEach: function (array, action) {
31.91 + for (var i = 0, j = array.length; i < j; i++)
31.92 + action(array[i]);
31.93 + },
31.94 +
31.95 + arrayIndexOf: function (array, item) {
31.96 + if (typeof Array.prototype.indexOf == "function")
31.97 + return Array.prototype.indexOf.call(array, item);
31.98 + for (var i = 0, j = array.length; i < j; i++)
31.99 + if (array[i] === item)
31.100 + return i;
31.101 + return -1;
31.102 + },
31.103 +
31.104 + arrayFirst: function (array, predicate, predicateOwner) {
31.105 + for (var i = 0, j = array.length; i < j; i++)
31.106 + if (predicate.call(predicateOwner, array[i]))
31.107 + return array[i];
31.108 + return null;
31.109 + },
31.110 +
31.111 + arrayRemoveItem: function (array, itemToRemove) {
31.112 + var index = ko.utils.arrayIndexOf(array, itemToRemove);
31.113 + if (index >= 0)
31.114 + array.splice(index, 1);
31.115 + },
31.116 +
31.117 + arrayGetDistinctValues: function (array) {
31.118 + array = array || [];
31.119 + var result = [];
31.120 + for (var i = 0, j = array.length; i < j; i++) {
31.121 + if (ko.utils.arrayIndexOf(result, array[i]) < 0)
31.122 + result.push(array[i]);
31.123 + }
31.124 + return result;
31.125 + },
31.126 +
31.127 + arrayMap: function (array, mapping) {
31.128 + array = array || [];
31.129 + var result = [];
31.130 + for (var i = 0, j = array.length; i < j; i++)
31.131 + result.push(mapping(array[i]));
31.132 + return result;
31.133 + },
31.134 +
31.135 + arrayFilter: function (array, predicate) {
31.136 + array = array || [];
31.137 + var result = [];
31.138 + for (var i = 0, j = array.length; i < j; i++)
31.139 + if (predicate(array[i]))
31.140 + result.push(array[i]);
31.141 + return result;
31.142 + },
31.143 +
31.144 + arrayPushAll: function (array, valuesToPush) {
31.145 + if (valuesToPush instanceof Array)
31.146 + array.push.apply(array, valuesToPush);
31.147 + else
31.148 + for (var i = 0, j = valuesToPush.length; i < j; i++)
31.149 + array.push(valuesToPush[i]);
31.150 + return array;
31.151 + },
31.152 +
31.153 + extend: function (target, source) {
31.154 + if (source) {
31.155 + for(var prop in source) {
31.156 + if(source.hasOwnProperty(prop)) {
31.157 + target[prop] = source[prop];
31.158 + }
31.159 + }
31.160 + }
31.161 + return target;
31.162 + },
31.163 +
31.164 + emptyDomNode: function (domNode) {
31.165 + while (domNode.firstChild) {
31.166 + ko.removeNode(domNode.firstChild);
31.167 + }
31.168 + },
31.169 +
31.170 + moveCleanedNodesToContainerElement: function(nodes) {
31.171 + // Ensure it's a real array, as we're about to reparent the nodes and
31.172 + // we don't want the underlying collection to change while we're doing that.
31.173 + var nodesArray = ko.utils.makeArray(nodes);
31.174 +
31.175 + var container = document.createElement('div');
31.176 + for (var i = 0, j = nodesArray.length; i < j; i++) {
31.177 + container.appendChild(ko.cleanNode(nodesArray[i]));
31.178 + }
31.179 + return container;
31.180 + },
31.181 +
31.182 + cloneNodes: function (nodesArray, shouldCleanNodes) {
31.183 + for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
31.184 + var clonedNode = nodesArray[i].cloneNode(true);
31.185 + newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
31.186 + }
31.187 + return newNodesArray;
31.188 + },
31.189 +
31.190 + setDomNodeChildren: function (domNode, childNodes) {
31.191 + ko.utils.emptyDomNode(domNode);
31.192 + if (childNodes) {
31.193 + for (var i = 0, j = childNodes.length; i < j; i++)
31.194 + domNode.appendChild(childNodes[i]);
31.195 + }
31.196 + },
31.197 +
31.198 + replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
31.199 + var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
31.200 + if (nodesToReplaceArray.length > 0) {
31.201 + var insertionPoint = nodesToReplaceArray[0];
31.202 + var parent = insertionPoint.parentNode;
31.203 + for (var i = 0, j = newNodesArray.length; i < j; i++)
31.204 + parent.insertBefore(newNodesArray[i], insertionPoint);
31.205 + for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
31.206 + ko.removeNode(nodesToReplaceArray[i]);
31.207 + }
31.208 + }
31.209 + },
31.210 +
31.211 + setOptionNodeSelectionState: function (optionNode, isSelected) {
31.212 + // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
31.213 + if (ieVersion < 7)
31.214 + optionNode.setAttribute("selected", isSelected);
31.215 + else
31.216 + optionNode.selected = isSelected;
31.217 + },
31.218 +
31.219 + stringTrim: function (string) {
31.220 + return (string || "").replace(stringTrimRegex, "");
31.221 + },
31.222 +
31.223 + stringTokenize: function (string, delimiter) {
31.224 + var result = [];
31.225 + var tokens = (string || "").split(delimiter);
31.226 + for (var i = 0, j = tokens.length; i < j; i++) {
31.227 + var trimmed = ko.utils.stringTrim(tokens[i]);
31.228 + if (trimmed !== "")
31.229 + result.push(trimmed);
31.230 + }
31.231 + return result;
31.232 + },
31.233 +
31.234 + stringStartsWith: function (string, startsWith) {
31.235 + string = string || "";
31.236 + if (startsWith.length > string.length)
31.237 + return false;
31.238 + return string.substring(0, startsWith.length) === startsWith;
31.239 + },
31.240 +
31.241 + domNodeIsContainedBy: function (node, containedByNode) {
31.242 + if (containedByNode.compareDocumentPosition)
31.243 + return (containedByNode.compareDocumentPosition(node) & 16) == 16;
31.244 + while (node != null) {
31.245 + if (node == containedByNode)
31.246 + return true;
31.247 + node = node.parentNode;
31.248 + }
31.249 + return false;
31.250 + },
31.251 +
31.252 + domNodeIsAttachedToDocument: function (node) {
31.253 + return ko.utils.domNodeIsContainedBy(node, node.ownerDocument);
31.254 + },
31.255 +
31.256 + tagNameLower: function(element) {
31.257 + // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
31.258 + // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
31.259 + // we don't need to do the .toLowerCase() as it will always be lower case anyway.
31.260 + return element && element.tagName && element.tagName.toLowerCase();
31.261 + },
31.262 +
31.263 + registerEventHandler: function (element, eventType, handler) {
31.264 + var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
31.265 + if (!mustUseAttachEvent && typeof jQuery != "undefined") {
31.266 + if (isClickOnCheckableElement(element, eventType)) {
31.267 + // For click events on checkboxes, jQuery interferes with the event handling in an awkward way:
31.268 + // it toggles the element checked state *after* the click event handlers run, whereas native
31.269 + // click events toggle the checked state *before* the event handler.
31.270 + // Fix this by intecepting the handler and applying the correct checkedness before it runs.
31.271 + var originalHandler = handler;
31.272 + handler = function(event, eventData) {
31.273 + var jQuerySuppliedCheckedState = this.checked;
31.274 + if (eventData)
31.275 + this.checked = eventData.checkedStateBeforeEvent !== true;
31.276 + originalHandler.call(this, event);
31.277 + this.checked = jQuerySuppliedCheckedState; // Restore the state jQuery applied
31.278 + };
31.279 + }
31.280 + jQuery(element)['bind'](eventType, handler);
31.281 + } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
31.282 + element.addEventListener(eventType, handler, false);
31.283 + else if (typeof element.attachEvent != "undefined")
31.284 + element.attachEvent("on" + eventType, function (event) {
31.285 + handler.call(element, event);
31.286 + });
31.287 + else
31.288 + throw new Error("Browser doesn't support addEventListener or attachEvent");
31.289 + },
31.290 +
31.291 + triggerEvent: function (element, eventType) {
31.292 + if (!(element && element.nodeType))
31.293 + throw new Error("element must be a DOM node when calling triggerEvent");
31.294 +
31.295 + if (typeof jQuery != "undefined") {
31.296 + var eventData = [];
31.297 + if (isClickOnCheckableElement(element, eventType)) {
31.298 + // Work around the jQuery "click events on checkboxes" issue described above by storing the original checked state before triggering the handler
31.299 + eventData.push({ checkedStateBeforeEvent: element.checked });
31.300 + }
31.301 + jQuery(element)['trigger'](eventType, eventData);
31.302 + } else if (typeof document.createEvent == "function") {
31.303 + if (typeof element.dispatchEvent == "function") {
31.304 + var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
31.305 + var event = document.createEvent(eventCategory);
31.306 + event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
31.307 + element.dispatchEvent(event);
31.308 + }
31.309 + else
31.310 + throw new Error("The supplied element doesn't support dispatchEvent");
31.311 + } else if (typeof element.fireEvent != "undefined") {
31.312 + // Unlike other browsers, IE doesn't change the checked state of checkboxes/radiobuttons when you trigger their "click" event
31.313 + // so to make it consistent, we'll do it manually here
31.314 + if (isClickOnCheckableElement(element, eventType))
31.315 + element.checked = element.checked !== true;
31.316 + element.fireEvent("on" + eventType);
31.317 + }
31.318 + else
31.319 + throw new Error("Browser doesn't support triggering events");
31.320 + },
31.321 +
31.322 + unwrapObservable: function (value) {
31.323 + return ko.isObservable(value) ? value() : value;
31.324 + },
31.325 +
31.326 + peekObservable: function (value) {
31.327 + return ko.isObservable(value) ? value.peek() : value;
31.328 + },
31.329 +
31.330 + toggleDomNodeCssClass: function (node, classNames, shouldHaveClass) {
31.331 + if (classNames) {
31.332 + var cssClassNameRegex = /[\w-]+/g,
31.333 + currentClassNames = node.className.match(cssClassNameRegex) || [];
31.334 + ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
31.335 + var indexOfClass = ko.utils.arrayIndexOf(currentClassNames, className);
31.336 + if (indexOfClass >= 0) {
31.337 + if (!shouldHaveClass)
31.338 + currentClassNames.splice(indexOfClass, 1);
31.339 + } else {
31.340 + if (shouldHaveClass)
31.341 + currentClassNames.push(className);
31.342 + }
31.343 + });
31.344 + node.className = currentClassNames.join(" ");
31.345 + }
31.346 + },
31.347 +
31.348 + setTextContent: function(element, textContent) {
31.349 + var value = ko.utils.unwrapObservable(textContent);
31.350 + if ((value === null) || (value === undefined))
31.351 + value = "";
31.352 +
31.353 + if (element.nodeType === 3) {
31.354 + element.data = value;
31.355 + } else {
31.356 + // We need there to be exactly one child: a text node.
31.357 + // If there are no children, more than one, or if it's not a text node,
31.358 + // we'll clear everything and create a single text node.
31.359 + var innerTextNode = ko.virtualElements.firstChild(element);
31.360 + if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
31.361 + ko.virtualElements.setDomNodeChildren(element, [document.createTextNode(value)]);
31.362 + } else {
31.363 + innerTextNode.data = value;
31.364 + }
31.365 +
31.366 + ko.utils.forceRefresh(element);
31.367 + }
31.368 + },
31.369 +
31.370 + setElementName: function(element, name) {
31.371 + element.name = name;
31.372 +
31.373 + // Workaround IE 6/7 issue
31.374 + // - https://github.com/SteveSanderson/knockout/issues/197
31.375 + // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
31.376 + if (ieVersion <= 7) {
31.377 + try {
31.378 + element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
31.379 + }
31.380 + catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
31.381 + }
31.382 + },
31.383 +
31.384 + forceRefresh: function(node) {
31.385 + // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
31.386 + if (ieVersion >= 9) {
31.387 + // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
31.388 + var elem = node.nodeType == 1 ? node : node.parentNode;
31.389 + if (elem.style)
31.390 + elem.style.zoom = elem.style.zoom;
31.391 + }
31.392 + },
31.393 +
31.394 + ensureSelectElementIsRenderedCorrectly: function(selectElement) {
31.395 + // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
31.396 + // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
31.397 + if (ieVersion >= 9) {
31.398 + var originalWidth = selectElement.style.width;
31.399 + selectElement.style.width = 0;
31.400 + selectElement.style.width = originalWidth;
31.401 + }
31.402 + },
31.403 +
31.404 + range: function (min, max) {
31.405 + min = ko.utils.unwrapObservable(min);
31.406 + max = ko.utils.unwrapObservable(max);
31.407 + var result = [];
31.408 + for (var i = min; i <= max; i++)
31.409 + result.push(i);
31.410 + return result;
31.411 + },
31.412 +
31.413 + makeArray: function(arrayLikeObject) {
31.414 + var result = [];
31.415 + for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
31.416 + result.push(arrayLikeObject[i]);
31.417 + };
31.418 + return result;
31.419 + },
31.420 +
31.421 + isIe6 : isIe6,
31.422 + isIe7 : isIe7,
31.423 + ieVersion : ieVersion,
31.424 +
31.425 + getFormFields: function(form, fieldName) {
31.426 + var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
31.427 + var isMatchingField = (typeof fieldName == 'string')
31.428 + ? function(field) { return field.name === fieldName }
31.429 + : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
31.430 + var matches = [];
31.431 + for (var i = fields.length - 1; i >= 0; i--) {
31.432 + if (isMatchingField(fields[i]))
31.433 + matches.push(fields[i]);
31.434 + };
31.435 + return matches;
31.436 + },
31.437 +
31.438 + parseJson: function (jsonString) {
31.439 + if (typeof jsonString == "string") {
31.440 + jsonString = ko.utils.stringTrim(jsonString);
31.441 + if (jsonString) {
31.442 + if (window.JSON && window.JSON.parse) // Use native parsing where available
31.443 + return window.JSON.parse(jsonString);
31.444 + return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
31.445 + }
31.446 + }
31.447 + return null;
31.448 + },
31.449 +
31.450 + stringifyJson: function (data, replacer, space) { // replacer and space are optional
31.451 + if ((typeof JSON == "undefined") || (typeof JSON.stringify == "undefined"))
31.452 + throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
31.453 + return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
31.454 + },
31.455 +
31.456 + postJson: function (urlOrForm, data, options) {
31.457 + options = options || {};
31.458 + var params = options['params'] || {};
31.459 + var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
31.460 + var url = urlOrForm;
31.461 +
31.462 + // If we were given a form, use its 'action' URL and pick out any requested field values
31.463 + if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
31.464 + var originalForm = urlOrForm;
31.465 + url = originalForm.action;
31.466 + for (var i = includeFields.length - 1; i >= 0; i--) {
31.467 + var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
31.468 + for (var j = fields.length - 1; j >= 0; j--)
31.469 + params[fields[j].name] = fields[j].value;
31.470 + }
31.471 + }
31.472 +
31.473 + data = ko.utils.unwrapObservable(data);
31.474 + var form = document.createElement("form");
31.475 + form.style.display = "none";
31.476 + form.action = url;
31.477 + form.method = "post";
31.478 + for (var key in data) {
31.479 + var input = document.createElement("input");
31.480 + input.name = key;
31.481 + input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
31.482 + form.appendChild(input);
31.483 + }
31.484 + for (var key in params) {
31.485 + var input = document.createElement("input");
31.486 + input.name = key;
31.487 + input.value = params[key];
31.488 + form.appendChild(input);
31.489 + }
31.490 + document.body.appendChild(form);
31.491 + options['submitter'] ? options['submitter'](form) : form.submit();
31.492 + setTimeout(function () { form.parentNode.removeChild(form); }, 0);
31.493 + }
31.494 + }
31.495 +})();
31.496 +
31.497 +ko.exportSymbol('utils', ko.utils);
31.498 +ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
31.499 +ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
31.500 +ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
31.501 +ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
31.502 +ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
31.503 +ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
31.504 +ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
31.505 +ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
31.506 +ko.exportSymbol('utils.extend', ko.utils.extend);
31.507 +ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
31.508 +ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
31.509 +ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
31.510 +ko.exportSymbol('utils.postJson', ko.utils.postJson);
31.511 +ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
31.512 +ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
31.513 +ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
31.514 +ko.exportSymbol('utils.range', ko.utils.range);
31.515 +ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
31.516 +ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
31.517 +ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
31.518 +
31.519 +if (!Function.prototype['bind']) {
31.520 + // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
31.521 + // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
31.522 + Function.prototype['bind'] = function (object) {
31.523 + var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
31.524 + return function () {
31.525 + return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
31.526 + };
31.527 + };
31.528 +}
31.529 +
31.530 +ko.utils.domData = new (function () {
31.531 + var uniqueId = 0;
31.532 + var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
31.533 + var dataStore = {};
31.534 + return {
31.535 + get: function (node, key) {
31.536 + var allDataForNode = ko.utils.domData.getAll(node, false);
31.537 + return allDataForNode === undefined ? undefined : allDataForNode[key];
31.538 + },
31.539 + set: function (node, key, value) {
31.540 + if (value === undefined) {
31.541 + // Make sure we don't actually create a new domData key if we are actually deleting a value
31.542 + if (ko.utils.domData.getAll(node, false) === undefined)
31.543 + return;
31.544 + }
31.545 + var allDataForNode = ko.utils.domData.getAll(node, true);
31.546 + allDataForNode[key] = value;
31.547 + },
31.548 + getAll: function (node, createIfNotFound) {
31.549 + var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
31.550 + var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
31.551 + if (!hasExistingDataStore) {
31.552 + if (!createIfNotFound)
31.553 + return undefined;
31.554 + dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
31.555 + dataStore[dataStoreKey] = {};
31.556 + }
31.557 + return dataStore[dataStoreKey];
31.558 + },
31.559 + clear: function (node) {
31.560 + var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
31.561 + if (dataStoreKey) {
31.562 + delete dataStore[dataStoreKey];
31.563 + node[dataStoreKeyExpandoPropertyName] = null;
31.564 + return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
31.565 + }
31.566 + return false;
31.567 + }
31.568 + }
31.569 +})();
31.570 +
31.571 +ko.exportSymbol('utils.domData', ko.utils.domData);
31.572 +ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
31.573 +
31.574 +ko.utils.domNodeDisposal = new (function () {
31.575 + var domDataKey = "__ko_domNodeDisposal__" + (new Date).getTime();
31.576 + var cleanableNodeTypes = { 1: true, 8: true, 9: true }; // Element, Comment, Document
31.577 + var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
31.578 +
31.579 + function getDisposeCallbacksCollection(node, createIfNotFound) {
31.580 + var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
31.581 + if ((allDisposeCallbacks === undefined) && createIfNotFound) {
31.582 + allDisposeCallbacks = [];
31.583 + ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
31.584 + }
31.585 + return allDisposeCallbacks;
31.586 + }
31.587 + function destroyCallbacksCollection(node) {
31.588 + ko.utils.domData.set(node, domDataKey, undefined);
31.589 + }
31.590 +
31.591 + function cleanSingleNode(node) {
31.592 + // Run all the dispose callbacks
31.593 + var callbacks = getDisposeCallbacksCollection(node, false);
31.594 + if (callbacks) {
31.595 + callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
31.596 + for (var i = 0; i < callbacks.length; i++)
31.597 + callbacks[i](node);
31.598 + }
31.599 +
31.600 + // Also erase the DOM data
31.601 + ko.utils.domData.clear(node);
31.602 +
31.603 + // Special support for jQuery here because it's so commonly used.
31.604 + // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
31.605 + // so notify it to tear down any resources associated with the node & descendants here.
31.606 + if ((typeof jQuery == "function") && (typeof jQuery['cleanData'] == "function"))
31.607 + jQuery['cleanData']([node]);
31.608 +
31.609 + // Also clear any immediate-child comment nodes, as these wouldn't have been found by
31.610 + // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
31.611 + if (cleanableNodeTypesWithDescendants[node.nodeType])
31.612 + cleanImmediateCommentTypeChildren(node);
31.613 + }
31.614 +
31.615 + function cleanImmediateCommentTypeChildren(nodeWithChildren) {
31.616 + var child, nextChild = nodeWithChildren.firstChild;
31.617 + while (child = nextChild) {
31.618 + nextChild = child.nextSibling;
31.619 + if (child.nodeType === 8)
31.620 + cleanSingleNode(child);
31.621 + }
31.622 + }
31.623 +
31.624 + return {
31.625 + addDisposeCallback : function(node, callback) {
31.626 + if (typeof callback != "function")
31.627 + throw new Error("Callback must be a function");
31.628 + getDisposeCallbacksCollection(node, true).push(callback);
31.629 + },
31.630 +
31.631 + removeDisposeCallback : function(node, callback) {
31.632 + var callbacksCollection = getDisposeCallbacksCollection(node, false);
31.633 + if (callbacksCollection) {
31.634 + ko.utils.arrayRemoveItem(callbacksCollection, callback);
31.635 + if (callbacksCollection.length == 0)
31.636 + destroyCallbacksCollection(node);
31.637 + }
31.638 + },
31.639 +
31.640 + cleanNode : function(node) {
31.641 + // First clean this node, where applicable
31.642 + if (cleanableNodeTypes[node.nodeType]) {
31.643 + cleanSingleNode(node);
31.644 +
31.645 + // ... then its descendants, where applicable
31.646 + if (cleanableNodeTypesWithDescendants[node.nodeType]) {
31.647 + // Clone the descendants list in case it changes during iteration
31.648 + var descendants = [];
31.649 + ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
31.650 + for (var i = 0, j = descendants.length; i < j; i++)
31.651 + cleanSingleNode(descendants[i]);
31.652 + }
31.653 + }
31.654 + return node;
31.655 + },
31.656 +
31.657 + removeNode : function(node) {
31.658 + ko.cleanNode(node);
31.659 + if (node.parentNode)
31.660 + node.parentNode.removeChild(node);
31.661 + }
31.662 + }
31.663 +})();
31.664 +ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
31.665 +ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
31.666 +ko.exportSymbol('cleanNode', ko.cleanNode);
31.667 +ko.exportSymbol('removeNode', ko.removeNode);
31.668 +ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
31.669 +ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
31.670 +ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
31.671 +(function () {
31.672 + var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
31.673 +
31.674 + function simpleHtmlParse(html) {
31.675 + // Based on jQuery's "clean" function, but only accounting for table-related elements.
31.676 + // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
31.677 +
31.678 + // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
31.679 + // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
31.680 + // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
31.681 + // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
31.682 +
31.683 + // Trim whitespace, otherwise indexOf won't work as expected
31.684 + var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
31.685 +
31.686 + // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
31.687 + var wrap = tags.match(/^<(thead|tbody|tfoot)/) && [1, "<table>", "</table>"] ||
31.688 + !tags.indexOf("<tr") && [2, "<table><tbody>", "</tbody></table>"] ||
31.689 + (!tags.indexOf("<td") || !tags.indexOf("<th")) && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
31.690 + /* anything else */ [0, "", ""];
31.691 +
31.692 + // Go to html and back, then peel off extra wrappers
31.693 + // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
31.694 + var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
31.695 + if (typeof window['innerShiv'] == "function") {
31.696 + div.appendChild(window['innerShiv'](markup));
31.697 + } else {
31.698 + div.innerHTML = markup;
31.699 + }
31.700 +
31.701 + // Move to the right depth
31.702 + while (wrap[0]--)
31.703 + div = div.lastChild;
31.704 +
31.705 + return ko.utils.makeArray(div.lastChild.childNodes);
31.706 + }
31.707 +
31.708 + function jQueryHtmlParse(html) {
31.709 + // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
31.710 + if (jQuery['parseHTML']) {
31.711 + return jQuery['parseHTML'](html);
31.712 + } else {
31.713 + // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
31.714 + var elems = jQuery['clean']([html]);
31.715 +
31.716 + // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
31.717 + // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
31.718 + // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
31.719 + if (elems && elems[0]) {
31.720 + // Find the top-most parent element that's a direct child of a document fragment
31.721 + var elem = elems[0];
31.722 + while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
31.723 + elem = elem.parentNode;
31.724 + // ... then detach it
31.725 + if (elem.parentNode)
31.726 + elem.parentNode.removeChild(elem);
31.727 + }
31.728 +
31.729 + return elems;
31.730 + }
31.731 + }
31.732 +
31.733 + ko.utils.parseHtmlFragment = function(html) {
31.734 + return typeof jQuery != 'undefined' ? jQueryHtmlParse(html) // As below, benefit from jQuery's optimisations where possible
31.735 + : simpleHtmlParse(html); // ... otherwise, this simple logic will do in most common cases.
31.736 + };
31.737 +
31.738 + ko.utils.setHtml = function(node, html) {
31.739 + ko.utils.emptyDomNode(node);
31.740 +
31.741 + // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
31.742 + html = ko.utils.unwrapObservable(html);
31.743 +
31.744 + if ((html !== null) && (html !== undefined)) {
31.745 + if (typeof html != 'string')
31.746 + html = html.toString();
31.747 +
31.748 + // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
31.749 + // for example <tr> elements which are not normally allowed to exist on their own.
31.750 + // If you've referenced jQuery we'll use that rather than duplicating its code.
31.751 + if (typeof jQuery != 'undefined') {
31.752 + jQuery(node)['html'](html);
31.753 + } else {
31.754 + // ... otherwise, use KO's own parsing logic.
31.755 + var parsedNodes = ko.utils.parseHtmlFragment(html);
31.756 + for (var i = 0; i < parsedNodes.length; i++)
31.757 + node.appendChild(parsedNodes[i]);
31.758 + }
31.759 + }
31.760 + };
31.761 +})();
31.762 +
31.763 +ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
31.764 +ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
31.765 +
31.766 +ko.memoization = (function () {
31.767 + var memos = {};
31.768 +
31.769 + function randomMax8HexChars() {
31.770 + return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
31.771 + }
31.772 + function generateRandomId() {
31.773 + return randomMax8HexChars() + randomMax8HexChars();
31.774 + }
31.775 + function findMemoNodes(rootNode, appendToArray) {
31.776 + if (!rootNode)
31.777 + return;
31.778 + if (rootNode.nodeType == 8) {
31.779 + var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
31.780 + if (memoId != null)
31.781 + appendToArray.push({ domNode: rootNode, memoId: memoId });
31.782 + } else if (rootNode.nodeType == 1) {
31.783 + for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
31.784 + findMemoNodes(childNodes[i], appendToArray);
31.785 + }
31.786 + }
31.787 +
31.788 + return {
31.789 + memoize: function (callback) {
31.790 + if (typeof callback != "function")
31.791 + throw new Error("You can only pass a function to ko.memoization.memoize()");
31.792 + var memoId = generateRandomId();
31.793 + memos[memoId] = callback;
31.794 + return "<!--[ko_memo:" + memoId + "]-->";
31.795 + },
31.796 +
31.797 + unmemoize: function (memoId, callbackParams) {
31.798 + var callback = memos[memoId];
31.799 + if (callback === undefined)
31.800 + throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
31.801 + try {
31.802 + callback.apply(null, callbackParams || []);
31.803 + return true;
31.804 + }
31.805 + finally { delete memos[memoId]; }
31.806 + },
31.807 +
31.808 + unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
31.809 + var memos = [];
31.810 + findMemoNodes(domNode, memos);
31.811 + for (var i = 0, j = memos.length; i < j; i++) {
31.812 + var node = memos[i].domNode;
31.813 + var combinedParams = [node];
31.814 + if (extraCallbackParamsArray)
31.815 + ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
31.816 + ko.memoization.unmemoize(memos[i].memoId, combinedParams);
31.817 + node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
31.818 + if (node.parentNode)
31.819 + node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
31.820 + }
31.821 + },
31.822 +
31.823 + parseMemoText: function (memoText) {
31.824 + var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
31.825 + return match ? match[1] : null;
31.826 + }
31.827 + };
31.828 +})();
31.829 +
31.830 +ko.exportSymbol('memoization', ko.memoization);
31.831 +ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
31.832 +ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
31.833 +ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
31.834 +ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
31.835 +ko.extenders = {
31.836 + 'throttle': function(target, timeout) {
31.837 + // Throttling means two things:
31.838 +
31.839 + // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
31.840 + // notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
31.841 + target['throttleEvaluation'] = timeout;
31.842 +
31.843 + // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
31.844 + // so the target cannot change value synchronously or faster than a certain rate
31.845 + var writeTimeoutInstance = null;
31.846 + return ko.dependentObservable({
31.847 + 'read': target,
31.848 + 'write': function(value) {
31.849 + clearTimeout(writeTimeoutInstance);
31.850 + writeTimeoutInstance = setTimeout(function() {
31.851 + target(value);
31.852 + }, timeout);
31.853 + }
31.854 + });
31.855 + },
31.856 +
31.857 + 'notify': function(target, notifyWhen) {
31.858 + target["equalityComparer"] = notifyWhen == "always"
31.859 + ? function() { return false } // Treat all values as not equal
31.860 + : ko.observable["fn"]["equalityComparer"];
31.861 + return target;
31.862 + }
31.863 +};
31.864 +
31.865 +function applyExtenders(requestedExtenders) {
31.866 + var target = this;
31.867 + if (requestedExtenders) {
31.868 + for (var key in requestedExtenders) {
31.869 + var extenderHandler = ko.extenders[key];
31.870 + if (typeof extenderHandler == 'function') {
31.871 + target = extenderHandler(target, requestedExtenders[key]);
31.872 + }
31.873 + }
31.874 + }
31.875 + return target;
31.876 +}
31.877 +
31.878 +ko.exportSymbol('extenders', ko.extenders);
31.879 +
31.880 +ko.subscription = function (target, callback, disposeCallback) {
31.881 + this.target = target;
31.882 + this.callback = callback;
31.883 + this.disposeCallback = disposeCallback;
31.884 + ko.exportProperty(this, 'dispose', this.dispose);
31.885 +};
31.886 +ko.subscription.prototype.dispose = function () {
31.887 + this.isDisposed = true;
31.888 + this.disposeCallback();
31.889 +};
31.890 +
31.891 +ko.subscribable = function () {
31.892 + this._subscriptions = {};
31.893 +
31.894 + ko.utils.extend(this, ko.subscribable['fn']);
31.895 + ko.exportProperty(this, 'subscribe', this.subscribe);
31.896 + ko.exportProperty(this, 'extend', this.extend);
31.897 + ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
31.898 +}
31.899 +
31.900 +var defaultEvent = "change";
31.901 +
31.902 +ko.subscribable['fn'] = {
31.903 + subscribe: function (callback, callbackTarget, event) {
31.904 + event = event || defaultEvent;
31.905 + var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
31.906 +
31.907 + var subscription = new ko.subscription(this, boundCallback, function () {
31.908 + ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);
31.909 + }.bind(this));
31.910 +
31.911 + if (!this._subscriptions[event])
31.912 + this._subscriptions[event] = [];
31.913 + this._subscriptions[event].push(subscription);
31.914 + return subscription;
31.915 + },
31.916 +
31.917 + "notifySubscribers": function (valueToNotify, event) {
31.918 + event = event || defaultEvent;
31.919 + if (this._subscriptions[event]) {
31.920 + ko.dependencyDetection.ignore(function() {
31.921 + ko.utils.arrayForEach(this._subscriptions[event].slice(0), function (subscription) {
31.922 + // In case a subscription was disposed during the arrayForEach cycle, check
31.923 + // for isDisposed on each subscription before invoking its callback
31.924 + if (subscription && (subscription.isDisposed !== true))
31.925 + subscription.callback(valueToNotify);
31.926 + });
31.927 + }, this);
31.928 + }
31.929 + },
31.930 +
31.931 + getSubscriptionsCount: function () {
31.932 + var total = 0;
31.933 + for (var eventName in this._subscriptions) {
31.934 + if (this._subscriptions.hasOwnProperty(eventName))
31.935 + total += this._subscriptions[eventName].length;
31.936 + }
31.937 + return total;
31.938 + },
31.939 +
31.940 + extend: applyExtenders
31.941 +};
31.942 +
31.943 +
31.944 +ko.isSubscribable = function (instance) {
31.945 + return typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
31.946 +};
31.947 +
31.948 +ko.exportSymbol('subscribable', ko.subscribable);
31.949 +ko.exportSymbol('isSubscribable', ko.isSubscribable);
31.950 +
31.951 +ko.dependencyDetection = (function () {
31.952 + var _frames = [];
31.953 +
31.954 + return {
31.955 + begin: function (callback) {
31.956 + _frames.push({ callback: callback, distinctDependencies:[] });
31.957 + },
31.958 +
31.959 + end: function () {
31.960 + _frames.pop();
31.961 + },
31.962 +
31.963 + registerDependency: function (subscribable) {
31.964 + if (!ko.isSubscribable(subscribable))
31.965 + throw new Error("Only subscribable things can act as dependencies");
31.966 + if (_frames.length > 0) {
31.967 + var topFrame = _frames[_frames.length - 1];
31.968 + if (!topFrame || ko.utils.arrayIndexOf(topFrame.distinctDependencies, subscribable) >= 0)
31.969 + return;
31.970 + topFrame.distinctDependencies.push(subscribable);
31.971 + topFrame.callback(subscribable);
31.972 + }
31.973 + },
31.974 +
31.975 + ignore: function(callback, callbackTarget, callbackArgs) {
31.976 + try {
31.977 + _frames.push(null);
31.978 + return callback.apply(callbackTarget, callbackArgs || []);
31.979 + } finally {
31.980 + _frames.pop();
31.981 + }
31.982 + }
31.983 + };
31.984 +})();
31.985 +var primitiveTypes = { 'undefined':true, 'boolean':true, 'number':true, 'string':true };
31.986 +
31.987 +ko.observable = function (initialValue) {
31.988 + var _latestValue = initialValue;
31.989 +
31.990 + function observable() {
31.991 + if (arguments.length > 0) {
31.992 + // Write
31.993 +
31.994 + // Ignore writes if the value hasn't changed
31.995 + if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {
31.996 + observable.valueWillMutate();
31.997 + _latestValue = arguments[0];
31.998 + if (DEBUG) observable._latestValue = _latestValue;
31.999 + observable.valueHasMutated();
31.1000 + }
31.1001 + return this; // Permits chained assignments
31.1002 + }
31.1003 + else {
31.1004 + // Read
31.1005 + ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
31.1006 + return _latestValue;
31.1007 + }
31.1008 + }
31.1009 + if (DEBUG) observable._latestValue = _latestValue;
31.1010 + ko.subscribable.call(observable);
31.1011 + observable.peek = function() { return _latestValue };
31.1012 + observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
31.1013 + observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
31.1014 + ko.utils.extend(observable, ko.observable['fn']);
31.1015 +
31.1016 + ko.exportProperty(observable, 'peek', observable.peek);
31.1017 + ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
31.1018 + ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
31.1019 +
31.1020 + return observable;
31.1021 +}
31.1022 +
31.1023 +ko.observable['fn'] = {
31.1024 + "equalityComparer": function valuesArePrimitiveAndEqual(a, b) {
31.1025 + var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
31.1026 + return oldValueIsPrimitive ? (a === b) : false;
31.1027 + }
31.1028 +};
31.1029 +
31.1030 +var protoProperty = ko.observable.protoProperty = "__ko_proto__";
31.1031 +ko.observable['fn'][protoProperty] = ko.observable;
31.1032 +
31.1033 +ko.hasPrototype = function(instance, prototype) {
31.1034 + if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
31.1035 + if (instance[protoProperty] === prototype) return true;
31.1036 + return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
31.1037 +};
31.1038 +
31.1039 +ko.isObservable = function (instance) {
31.1040 + return ko.hasPrototype(instance, ko.observable);
31.1041 +}
31.1042 +ko.isWriteableObservable = function (instance) {
31.1043 + // Observable
31.1044 + if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
31.1045 + return true;
31.1046 + // Writeable dependent observable
31.1047 + if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
31.1048 + return true;
31.1049 + // Anything else
31.1050 + return false;
31.1051 +}
31.1052 +
31.1053 +
31.1054 +ko.exportSymbol('observable', ko.observable);
31.1055 +ko.exportSymbol('isObservable', ko.isObservable);
31.1056 +ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
31.1057 +ko.observableArray = function (initialValues) {
31.1058 + if (arguments.length == 0) {
31.1059 + // Zero-parameter constructor initializes to empty array
31.1060 + initialValues = [];
31.1061 + }
31.1062 + if ((initialValues !== null) && (initialValues !== undefined) && !('length' in initialValues))
31.1063 + throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
31.1064 +
31.1065 + var result = ko.observable(initialValues);
31.1066 + ko.utils.extend(result, ko.observableArray['fn']);
31.1067 + return result;
31.1068 +}
31.1069 +
31.1070 +ko.observableArray['fn'] = {
31.1071 + 'remove': function (valueOrPredicate) {
31.1072 + var underlyingArray = this.peek();
31.1073 + var removedValues = [];
31.1074 + var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
31.1075 + for (var i = 0; i < underlyingArray.length; i++) {
31.1076 + var value = underlyingArray[i];
31.1077 + if (predicate(value)) {
31.1078 + if (removedValues.length === 0) {
31.1079 + this.valueWillMutate();
31.1080 + }
31.1081 + removedValues.push(value);
31.1082 + underlyingArray.splice(i, 1);
31.1083 + i--;
31.1084 + }
31.1085 + }
31.1086 + if (removedValues.length) {
31.1087 + this.valueHasMutated();
31.1088 + }
31.1089 + return removedValues;
31.1090 + },
31.1091 +
31.1092 + 'removeAll': function (arrayOfValues) {
31.1093 + // If you passed zero args, we remove everything
31.1094 + if (arrayOfValues === undefined) {
31.1095 + var underlyingArray = this.peek();
31.1096 + var allValues = underlyingArray.slice(0);
31.1097 + this.valueWillMutate();
31.1098 + underlyingArray.splice(0, underlyingArray.length);
31.1099 + this.valueHasMutated();
31.1100 + return allValues;
31.1101 + }
31.1102 + // If you passed an arg, we interpret it as an array of entries to remove
31.1103 + if (!arrayOfValues)
31.1104 + return [];
31.1105 + return this['remove'](function (value) {
31.1106 + return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
31.1107 + });
31.1108 + },
31.1109 +
31.1110 + 'destroy': function (valueOrPredicate) {
31.1111 + var underlyingArray = this.peek();
31.1112 + var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
31.1113 + this.valueWillMutate();
31.1114 + for (var i = underlyingArray.length - 1; i >= 0; i--) {
31.1115 + var value = underlyingArray[i];
31.1116 + if (predicate(value))
31.1117 + underlyingArray[i]["_destroy"] = true;
31.1118 + }
31.1119 + this.valueHasMutated();
31.1120 + },
31.1121 +
31.1122 + 'destroyAll': function (arrayOfValues) {
31.1123 + // If you passed zero args, we destroy everything
31.1124 + if (arrayOfValues === undefined)
31.1125 + return this['destroy'](function() { return true });
31.1126 +
31.1127 + // If you passed an arg, we interpret it as an array of entries to destroy
31.1128 + if (!arrayOfValues)
31.1129 + return [];
31.1130 + return this['destroy'](function (value) {
31.1131 + return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
31.1132 + });
31.1133 + },
31.1134 +
31.1135 + 'indexOf': function (item) {
31.1136 + var underlyingArray = this();
31.1137 + return ko.utils.arrayIndexOf(underlyingArray, item);
31.1138 + },
31.1139 +
31.1140 + 'replace': function(oldItem, newItem) {
31.1141 + var index = this['indexOf'](oldItem);
31.1142 + if (index >= 0) {
31.1143 + this.valueWillMutate();
31.1144 + this.peek()[index] = newItem;
31.1145 + this.valueHasMutated();
31.1146 + }
31.1147 + }
31.1148 +}
31.1149 +
31.1150 +// Populate ko.observableArray.fn with read/write functions from native arrays
31.1151 +// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
31.1152 +// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
31.1153 +ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
31.1154 + ko.observableArray['fn'][methodName] = function () {
31.1155 + // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
31.1156 + // (for consistency with mutating regular observables)
31.1157 + var underlyingArray = this.peek();
31.1158 + this.valueWillMutate();
31.1159 + var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
31.1160 + this.valueHasMutated();
31.1161 + return methodCallResult;
31.1162 + };
31.1163 +});
31.1164 +
31.1165 +// Populate ko.observableArray.fn with read-only functions from native arrays
31.1166 +ko.utils.arrayForEach(["slice"], function (methodName) {
31.1167 + ko.observableArray['fn'][methodName] = function () {
31.1168 + var underlyingArray = this();
31.1169 + return underlyingArray[methodName].apply(underlyingArray, arguments);
31.1170 + };
31.1171 +});
31.1172 +
31.1173 +ko.exportSymbol('observableArray', ko.observableArray);
31.1174 +ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
31.1175 + var _latestValue,
31.1176 + _hasBeenEvaluated = false,
31.1177 + _isBeingEvaluated = false,
31.1178 + readFunction = evaluatorFunctionOrOptions;
31.1179 +
31.1180 + if (readFunction && typeof readFunction == "object") {
31.1181 + // Single-parameter syntax - everything is on this "options" param
31.1182 + options = readFunction;
31.1183 + readFunction = options["read"];
31.1184 + } else {
31.1185 + // Multi-parameter syntax - construct the options according to the params passed
31.1186 + options = options || {};
31.1187 + if (!readFunction)
31.1188 + readFunction = options["read"];
31.1189 + }
31.1190 + if (typeof readFunction != "function")
31.1191 + throw new Error("Pass a function that returns the value of the ko.computed");
31.1192 +
31.1193 + function addSubscriptionToDependency(subscribable) {
31.1194 + _subscriptionsToDependencies.push(subscribable.subscribe(evaluatePossiblyAsync));
31.1195 + }
31.1196 +
31.1197 + function disposeAllSubscriptionsToDependencies() {
31.1198 + ko.utils.arrayForEach(_subscriptionsToDependencies, function (subscription) {
31.1199 + subscription.dispose();
31.1200 + });
31.1201 + _subscriptionsToDependencies = [];
31.1202 + }
31.1203 +
31.1204 + function evaluatePossiblyAsync() {
31.1205 + var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
31.1206 + if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
31.1207 + clearTimeout(evaluationTimeoutInstance);
31.1208 + evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
31.1209 + } else
31.1210 + evaluateImmediate();
31.1211 + }
31.1212 +
31.1213 + function evaluateImmediate() {
31.1214 + if (_isBeingEvaluated) {
31.1215 + // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
31.1216 + // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
31.1217 + // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
31.1218 + // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
31.1219 + return;
31.1220 + }
31.1221 +
31.1222 + // Don't dispose on first evaluation, because the "disposeWhen" callback might
31.1223 + // e.g., dispose when the associated DOM element isn't in the doc, and it's not
31.1224 + // going to be in the doc until *after* the first evaluation
31.1225 + if (_hasBeenEvaluated && disposeWhen()) {
31.1226 + dispose();
31.1227 + return;
31.1228 + }
31.1229 +
31.1230 + _isBeingEvaluated = true;
31.1231 + try {
31.1232 + // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
31.1233 + // Then, during evaluation, we cross off any that are in fact still being used.
31.1234 + var disposalCandidates = ko.utils.arrayMap(_subscriptionsToDependencies, function(item) {return item.target;});
31.1235 +
31.1236 + ko.dependencyDetection.begin(function(subscribable) {
31.1237 + var inOld;
31.1238 + if ((inOld = ko.utils.arrayIndexOf(disposalCandidates, subscribable)) >= 0)
31.1239 + disposalCandidates[inOld] = undefined; // Don't want to dispose this subscription, as it's still being used
31.1240 + else
31.1241 + addSubscriptionToDependency(subscribable); // Brand new subscription - add it
31.1242 + });
31.1243 +
31.1244 + var newValue = readFunction.call(evaluatorFunctionTarget);
31.1245 +
31.1246 + // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
31.1247 + for (var i = disposalCandidates.length - 1; i >= 0; i--) {
31.1248 + if (disposalCandidates[i])
31.1249 + _subscriptionsToDependencies.splice(i, 1)[0].dispose();
31.1250 + }
31.1251 + _hasBeenEvaluated = true;
31.1252 +
31.1253 + dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
31.1254 + _latestValue = newValue;
31.1255 + if (DEBUG) dependentObservable._latestValue = _latestValue;
31.1256 + } finally {
31.1257 + ko.dependencyDetection.end();
31.1258 + }
31.1259 +
31.1260 + dependentObservable["notifySubscribers"](_latestValue);
31.1261 + _isBeingEvaluated = false;
31.1262 + if (!_subscriptionsToDependencies.length)
31.1263 + dispose();
31.1264 + }
31.1265 +
31.1266 + function dependentObservable() {
31.1267 + if (arguments.length > 0) {
31.1268 + if (typeof writeFunction === "function") {
31.1269 + // Writing a value
31.1270 + writeFunction.apply(evaluatorFunctionTarget, arguments);
31.1271 + } else {
31.1272 + throw new Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
31.1273 + }
31.1274 + return this; // Permits chained assignments
31.1275 + } else {
31.1276 + // Reading the value
31.1277 + if (!_hasBeenEvaluated)
31.1278 + evaluateImmediate();
31.1279 + ko.dependencyDetection.registerDependency(dependentObservable);
31.1280 + return _latestValue;
31.1281 + }
31.1282 + }
31.1283 +
31.1284 + function peek() {
31.1285 + if (!_hasBeenEvaluated)
31.1286 + evaluateImmediate();
31.1287 + return _latestValue;
31.1288 + }
31.1289 +
31.1290 + function isActive() {
31.1291 + return !_hasBeenEvaluated || _subscriptionsToDependencies.length > 0;
31.1292 + }
31.1293 +
31.1294 + // By here, "options" is always non-null
31.1295 + var writeFunction = options["write"],
31.1296 + disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
31.1297 + disposeWhen = options["disposeWhen"] || options.disposeWhen || function() { return false; },
31.1298 + dispose = disposeAllSubscriptionsToDependencies,
31.1299 + _subscriptionsToDependencies = [],
31.1300 + evaluationTimeoutInstance = null;
31.1301 +
31.1302 + if (!evaluatorFunctionTarget)
31.1303 + evaluatorFunctionTarget = options["owner"];
31.1304 +
31.1305 + dependentObservable.peek = peek;
31.1306 + dependentObservable.getDependenciesCount = function () { return _subscriptionsToDependencies.length; };
31.1307 + dependentObservable.hasWriteFunction = typeof options["write"] === "function";
31.1308 + dependentObservable.dispose = function () { dispose(); };
31.1309 + dependentObservable.isActive = isActive;
31.1310 + dependentObservable.valueHasMutated = function() {
31.1311 + _hasBeenEvaluated = false;
31.1312 + evaluateImmediate();
31.1313 + };
31.1314 +
31.1315 + ko.subscribable.call(dependentObservable);
31.1316 + ko.utils.extend(dependentObservable, ko.dependentObservable['fn']);
31.1317 +
31.1318 + ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
31.1319 + ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
31.1320 + ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
31.1321 + ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
31.1322 +
31.1323 + // Evaluate, unless deferEvaluation is true
31.1324 + if (options['deferEvaluation'] !== true)
31.1325 + evaluateImmediate();
31.1326 +
31.1327 + // Build "disposeWhenNodeIsRemoved" and "disposeWhenNodeIsRemovedCallback" option values.
31.1328 + // But skip if isActive is false (there will never be any dependencies to dispose).
31.1329 + // (Note: "disposeWhenNodeIsRemoved" option both proactively disposes as soon as the node is removed using ko.removeNode(),
31.1330 + // plus adds a "disposeWhen" callback that, on each evaluation, disposes if the node was removed by some other means.)
31.1331 + if (disposeWhenNodeIsRemoved && isActive()) {
31.1332 + dispose = function() {
31.1333 + ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, arguments.callee);
31.1334 + disposeAllSubscriptionsToDependencies();
31.1335 + };
31.1336 + ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
31.1337 + var existingDisposeWhenFunction = disposeWhen;
31.1338 + disposeWhen = function () {
31.1339 + return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || existingDisposeWhenFunction();
31.1340 + }
31.1341 + }
31.1342 +
31.1343 + return dependentObservable;
31.1344 +};
31.1345 +
31.1346 +ko.isComputed = function(instance) {
31.1347 + return ko.hasPrototype(instance, ko.dependentObservable);
31.1348 +};
31.1349 +
31.1350 +var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
31.1351 +ko.dependentObservable[protoProp] = ko.observable;
31.1352 +
31.1353 +ko.dependentObservable['fn'] = {};
31.1354 +ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
31.1355 +
31.1356 +ko.exportSymbol('dependentObservable', ko.dependentObservable);
31.1357 +ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
31.1358 +ko.exportSymbol('isComputed', ko.isComputed);
31.1359 +
31.1360 +(function() {
31.1361 + var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
31.1362 +
31.1363 + ko.toJS = function(rootObject) {
31.1364 + if (arguments.length == 0)
31.1365 + throw new Error("When calling ko.toJS, pass the object you want to convert.");
31.1366 +
31.1367 + // We just unwrap everything at every level in the object graph
31.1368 + return mapJsObjectGraph(rootObject, function(valueToMap) {
31.1369 + // Loop because an observable's value might in turn be another observable wrapper
31.1370 + for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
31.1371 + valueToMap = valueToMap();
31.1372 + return valueToMap;
31.1373 + });
31.1374 + };
31.1375 +
31.1376 + ko.toJSON = function(rootObject, replacer, space) { // replacer and space are optional
31.1377 + var plainJavaScriptObject = ko.toJS(rootObject);
31.1378 + return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
31.1379 + };
31.1380 +
31.1381 + function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
31.1382 + visitedObjects = visitedObjects || new objectLookup();
31.1383 +
31.1384 + rootObject = mapInputCallback(rootObject);
31.1385 + var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date));
31.1386 + if (!canHaveProperties)
31.1387 + return rootObject;
31.1388 +
31.1389 + var outputProperties = rootObject instanceof Array ? [] : {};
31.1390 + visitedObjects.save(rootObject, outputProperties);
31.1391 +
31.1392 + visitPropertiesOrArrayEntries(rootObject, function(indexer) {
31.1393 + var propertyValue = mapInputCallback(rootObject[indexer]);
31.1394 +
31.1395 + switch (typeof propertyValue) {
31.1396 + case "boolean":
31.1397 + case "number":
31.1398 + case "string":
31.1399 + case "function":
31.1400 + outputProperties[indexer] = propertyValue;
31.1401 + break;
31.1402 + case "object":
31.1403 + case "undefined":
31.1404 + var previouslyMappedValue = visitedObjects.get(propertyValue);
31.1405 + outputProperties[indexer] = (previouslyMappedValue !== undefined)
31.1406 + ? previouslyMappedValue
31.1407 + : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
31.1408 + break;
31.1409 + }
31.1410 + });
31.1411 +
31.1412 + return outputProperties;
31.1413 + }
31.1414 +
31.1415 + function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
31.1416 + if (rootObject instanceof Array) {
31.1417 + for (var i = 0; i < rootObject.length; i++)
31.1418 + visitorCallback(i);
31.1419 +
31.1420 + // For arrays, also respect toJSON property for custom mappings (fixes #278)
31.1421 + if (typeof rootObject['toJSON'] == 'function')
31.1422 + visitorCallback('toJSON');
31.1423 + } else {
31.1424 + for (var propertyName in rootObject)
31.1425 + visitorCallback(propertyName);
31.1426 + }
31.1427 + };
31.1428 +
31.1429 + function objectLookup() {
31.1430 + var keys = [];
31.1431 + var values = [];
31.1432 + this.save = function(key, value) {
31.1433 + var existingIndex = ko.utils.arrayIndexOf(keys, key);
31.1434 + if (existingIndex >= 0)
31.1435 + values[existingIndex] = value;
31.1436 + else {
31.1437 + keys.push(key);
31.1438 + values.push(value);
31.1439 + }
31.1440 + };
31.1441 + this.get = function(key) {
31.1442 + var existingIndex = ko.utils.arrayIndexOf(keys, key);
31.1443 + return (existingIndex >= 0) ? values[existingIndex] : undefined;
31.1444 + };
31.1445 + };
31.1446 +})();
31.1447 +
31.1448 +ko.exportSymbol('toJS', ko.toJS);
31.1449 +ko.exportSymbol('toJSON', ko.toJSON);
31.1450 +(function () {
31.1451 + var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
31.1452 +
31.1453 + // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
31.1454 + // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
31.1455 + // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
31.1456 + ko.selectExtensions = {
31.1457 + readValue : function(element) {
31.1458 + switch (ko.utils.tagNameLower(element)) {
31.1459 + case 'option':
31.1460 + if (element[hasDomDataExpandoProperty] === true)
31.1461 + return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
31.1462 + return ko.utils.ieVersion <= 7
31.1463 + ? (element.getAttributeNode('value').specified ? element.value : element.text)
31.1464 + : element.value;
31.1465 + case 'select':
31.1466 + return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
31.1467 + default:
31.1468 + return element.value;
31.1469 + }
31.1470 + },
31.1471 +
31.1472 + writeValue: function(element, value) {
31.1473 + switch (ko.utils.tagNameLower(element)) {
31.1474 + case 'option':
31.1475 + switch(typeof value) {
31.1476 + case "string":
31.1477 + ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
31.1478 + if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
31.1479 + delete element[hasDomDataExpandoProperty];
31.1480 + }
31.1481 + element.value = value;
31.1482 + break;
31.1483 + default:
31.1484 + // Store arbitrary object using DomData
31.1485 + ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
31.1486 + element[hasDomDataExpandoProperty] = true;
31.1487 +
31.1488 + // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
31.1489 + element.value = typeof value === "number" ? value : "";
31.1490 + break;
31.1491 + }
31.1492 + break;
31.1493 + case 'select':
31.1494 + for (var i = element.options.length - 1; i >= 0; i--) {
31.1495 + if (ko.selectExtensions.readValue(element.options[i]) == value) {
31.1496 + element.selectedIndex = i;
31.1497 + break;
31.1498 + }
31.1499 + }
31.1500 + break;
31.1501 + default:
31.1502 + if ((value === null) || (value === undefined))
31.1503 + value = "";
31.1504 + element.value = value;
31.1505 + break;
31.1506 + }
31.1507 + }
31.1508 + };
31.1509 +})();
31.1510 +
31.1511 +ko.exportSymbol('selectExtensions', ko.selectExtensions);
31.1512 +ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
31.1513 +ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
31.1514 +ko.expressionRewriting = (function () {
31.1515 + var restoreCapturedTokensRegex = /\@ko_token_(\d+)\@/g;
31.1516 + var javaScriptReservedWords = ["true", "false"];
31.1517 +
31.1518 + // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
31.1519 + // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
31.1520 + var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
31.1521 +
31.1522 + function restoreTokens(string, tokens) {
31.1523 + var prevValue = null;
31.1524 + while (string != prevValue) { // Keep restoring tokens until it no longer makes a difference (they may be nested)
31.1525 + prevValue = string;
31.1526 + string = string.replace(restoreCapturedTokensRegex, function (match, tokenIndex) {
31.1527 + return tokens[tokenIndex];
31.1528 + });
31.1529 + }
31.1530 + return string;
31.1531 + }
31.1532 +
31.1533 + function getWriteableValue(expression) {
31.1534 + if (ko.utils.arrayIndexOf(javaScriptReservedWords, ko.utils.stringTrim(expression).toLowerCase()) >= 0)
31.1535 + return false;
31.1536 + var match = expression.match(javaScriptAssignmentTarget);
31.1537 + return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
31.1538 + }
31.1539 +
31.1540 + function ensureQuoted(key) {
31.1541 + var trimmedKey = ko.utils.stringTrim(key);
31.1542 + switch (trimmedKey.length && trimmedKey.charAt(0)) {
31.1543 + case "'":
31.1544 + case '"':
31.1545 + return key;
31.1546 + default:
31.1547 + return "'" + trimmedKey + "'";
31.1548 + }
31.1549 + }
31.1550 +
31.1551 + return {
31.1552 + bindingRewriteValidators: [],
31.1553 +
31.1554 + parseObjectLiteral: function(objectLiteralString) {
31.1555 + // A full tokeniser+lexer would add too much weight to this library, so here's a simple parser
31.1556 + // that is sufficient just to split an object literal string into a set of top-level key-value pairs
31.1557 +
31.1558 + var str = ko.utils.stringTrim(objectLiteralString);
31.1559 + if (str.length < 3)
31.1560 + return [];
31.1561 + if (str.charAt(0) === "{")// Ignore any braces surrounding the whole object literal
31.1562 + str = str.substring(1, str.length - 1);
31.1563 +
31.1564 + // Pull out any string literals and regex literals
31.1565 + var tokens = [];
31.1566 + var tokenStart = null, tokenEndChar;
31.1567 + for (var position = 0; position < str.length; position++) {
31.1568 + var c = str.charAt(position);
31.1569 + if (tokenStart === null) {
31.1570 + switch (c) {
31.1571 + case '"':
31.1572 + case "'":
31.1573 + case "/":
31.1574 + tokenStart = position;
31.1575 + tokenEndChar = c;
31.1576 + break;
31.1577 + }
31.1578 + } else if ((c == tokenEndChar) && (str.charAt(position - 1) !== "\\")) {
31.1579 + var token = str.substring(tokenStart, position + 1);
31.1580 + tokens.push(token);
31.1581 + var replacement = "@ko_token_" + (tokens.length - 1) + "@";
31.1582 + str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
31.1583 + position -= (token.length - replacement.length);
31.1584 + tokenStart = null;
31.1585 + }
31.1586 + }
31.1587 +
31.1588 + // Next pull out balanced paren, brace, and bracket blocks
31.1589 + tokenStart = null;
31.1590 + tokenEndChar = null;
31.1591 + var tokenDepth = 0, tokenStartChar = null;
31.1592 + for (var position = 0; position < str.length; position++) {
31.1593 + var c = str.charAt(position);
31.1594 + if (tokenStart === null) {
31.1595 + switch (c) {
31.1596 + case "{": tokenStart = position; tokenStartChar = c;
31.1597 + tokenEndChar = "}";
31.1598 + break;
31.1599 + case "(": tokenStart = position; tokenStartChar = c;
31.1600 + tokenEndChar = ")";
31.1601 + break;
31.1602 + case "[": tokenStart = position; tokenStartChar = c;
31.1603 + tokenEndChar = "]";
31.1604 + break;
31.1605 + }
31.1606 + }
31.1607 +
31.1608 + if (c === tokenStartChar)
31.1609 + tokenDepth++;
31.1610 + else if (c === tokenEndChar) {
31.1611 + tokenDepth--;
31.1612 + if (tokenDepth === 0) {
31.1613 + var token = str.substring(tokenStart, position + 1);
31.1614 + tokens.push(token);
31.1615 + var replacement = "@ko_token_" + (tokens.length - 1) + "@";
31.1616 + str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
31.1617 + position -= (token.length - replacement.length);
31.1618 + tokenStart = null;
31.1619 + }
31.1620 + }
31.1621 + }
31.1622 +
31.1623 + // Now we can safely split on commas to get the key/value pairs
31.1624 + var result = [];
31.1625 + var keyValuePairs = str.split(",");
31.1626 + for (var i = 0, j = keyValuePairs.length; i < j; i++) {
31.1627 + var pair = keyValuePairs[i];
31.1628 + var colonPos = pair.indexOf(":");
31.1629 + if ((colonPos > 0) && (colonPos < pair.length - 1)) {
31.1630 + var key = pair.substring(0, colonPos);
31.1631 + var value = pair.substring(colonPos + 1);
31.1632 + result.push({ 'key': restoreTokens(key, tokens), 'value': restoreTokens(value, tokens) });
31.1633 + } else {
31.1634 + result.push({ 'unknown': restoreTokens(pair, tokens) });
31.1635 + }
31.1636 + }
31.1637 + return result;
31.1638 + },
31.1639 +
31.1640 + preProcessBindings: function (objectLiteralStringOrKeyValueArray) {
31.1641 + var keyValueArray = typeof objectLiteralStringOrKeyValueArray === "string"
31.1642 + ? ko.expressionRewriting.parseObjectLiteral(objectLiteralStringOrKeyValueArray)
31.1643 + : objectLiteralStringOrKeyValueArray;
31.1644 + var resultStrings = [], propertyAccessorResultStrings = [];
31.1645 +
31.1646 + var keyValueEntry;
31.1647 + for (var i = 0; keyValueEntry = keyValueArray[i]; i++) {
31.1648 + if (resultStrings.length > 0)
31.1649 + resultStrings.push(",");
31.1650 +
31.1651 + if (keyValueEntry['key']) {
31.1652 + var quotedKey = ensureQuoted(keyValueEntry['key']), val = keyValueEntry['value'];
31.1653 + resultStrings.push(quotedKey);
31.1654 + resultStrings.push(":");
31.1655 + resultStrings.push(val);
31.1656 +
31.1657 + if (val = getWriteableValue(ko.utils.stringTrim(val))) {
31.1658 + if (propertyAccessorResultStrings.length > 0)
31.1659 + propertyAccessorResultStrings.push(", ");
31.1660 + propertyAccessorResultStrings.push(quotedKey + " : function(__ko_value) { " + val + " = __ko_value; }");
31.1661 + }
31.1662 + } else if (keyValueEntry['unknown']) {
31.1663 + resultStrings.push(keyValueEntry['unknown']);
31.1664 + }
31.1665 + }
31.1666 +
31.1667 + var combinedResult = resultStrings.join("");
31.1668 + if (propertyAccessorResultStrings.length > 0) {
31.1669 + var allPropertyAccessors = propertyAccessorResultStrings.join("");
31.1670 + combinedResult = combinedResult + ", '_ko_property_writers' : { " + allPropertyAccessors + " } ";
31.1671 + }
31.1672 +
31.1673 + return combinedResult;
31.1674 + },
31.1675 +
31.1676 + keyValueArrayContainsKey: function(keyValueArray, key) {
31.1677 + for (var i = 0; i < keyValueArray.length; i++)
31.1678 + if (ko.utils.stringTrim(keyValueArray[i]['key']) == key)
31.1679 + return true;
31.1680 + return false;
31.1681 + },
31.1682 +
31.1683 + // Internal, private KO utility for updating model properties from within bindings
31.1684 + // property: If the property being updated is (or might be) an observable, pass it here
31.1685 + // If it turns out to be a writable observable, it will be written to directly
31.1686 + // allBindingsAccessor: All bindings in the current execution context.
31.1687 + // This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
31.1688 + // key: The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
31.1689 + // value: The value to be written
31.1690 + // checkIfDifferent: If true, and if the property being written is a writable observable, the value will only be written if
31.1691 + // it is !== existing value on that writable observable
31.1692 + writeValueToProperty: function(property, allBindingsAccessor, key, value, checkIfDifferent) {
31.1693 + if (!property || !ko.isWriteableObservable(property)) {
31.1694 + var propWriters = allBindingsAccessor()['_ko_property_writers'];
31.1695 + if (propWriters && propWriters[key])
31.1696 + propWriters[key](value);
31.1697 + } else if (!checkIfDifferent || property.peek() !== value) {
31.1698 + property(value);
31.1699 + }
31.1700 + }
31.1701 + };
31.1702 +})();
31.1703 +
31.1704 +ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
31.1705 +ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
31.1706 +ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
31.1707 +ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
31.1708 +
31.1709 +// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
31.1710 +// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
31.1711 +ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
31.1712 +ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);(function() {
31.1713 + // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
31.1714 + // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
31.1715 + // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
31.1716 + // of that virtual hierarchy
31.1717 + //
31.1718 + // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
31.1719 + // without having to scatter special cases all over the binding and templating code.
31.1720 +
31.1721 + // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
31.1722 + // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
31.1723 + // So, use node.text where available, and node.nodeValue elsewhere
31.1724 + var commentNodesHaveTextProperty = document.createComment("test").text === "<!--test-->";
31.1725 +
31.1726 + var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*-->$/ : /^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/;
31.1727 + var endCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
31.1728 + var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
31.1729 +
31.1730 + function isStartComment(node) {
31.1731 + return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
31.1732 + }
31.1733 +
31.1734 + function isEndComment(node) {
31.1735 + return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(endCommentRegex);
31.1736 + }
31.1737 +
31.1738 + function getVirtualChildren(startComment, allowUnbalanced) {
31.1739 + var currentNode = startComment;
31.1740 + var depth = 1;
31.1741 + var children = [];
31.1742 + while (currentNode = currentNode.nextSibling) {
31.1743 + if (isEndComment(currentNode)) {
31.1744 + depth--;
31.1745 + if (depth === 0)
31.1746 + return children;
31.1747 + }
31.1748 +
31.1749 + children.push(currentNode);
31.1750 +
31.1751 + if (isStartComment(currentNode))
31.1752 + depth++;
31.1753 + }
31.1754 + if (!allowUnbalanced)
31.1755 + throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
31.1756 + return null;
31.1757 + }
31.1758 +
31.1759 + function getMatchingEndComment(startComment, allowUnbalanced) {
31.1760 + var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
31.1761 + if (allVirtualChildren) {
31.1762 + if (allVirtualChildren.length > 0)
31.1763 + return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
31.1764 + return startComment.nextSibling;
31.1765 + } else
31.1766 + return null; // Must have no matching end comment, and allowUnbalanced is true
31.1767 + }
31.1768 +
31.1769 + function getUnbalancedChildTags(node) {
31.1770 + // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
31.1771 + // from <div>OK</div><!-- /ko --><!-- /ko -->, returns: <!-- /ko --><!-- /ko -->
31.1772 + var childNode = node.firstChild, captureRemaining = null;
31.1773 + if (childNode) {
31.1774 + do {
31.1775 + if (captureRemaining) // We already hit an unbalanced node and are now just scooping up all subsequent nodes
31.1776 + captureRemaining.push(childNode);
31.1777 + else if (isStartComment(childNode)) {
31.1778 + var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
31.1779 + if (matchingEndComment) // It's a balanced tag, so skip immediately to the end of this virtual set
31.1780 + childNode = matchingEndComment;
31.1781 + else
31.1782 + captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
31.1783 + } else if (isEndComment(childNode)) {
31.1784 + captureRemaining = [childNode]; // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
31.1785 + }
31.1786 + } while (childNode = childNode.nextSibling);
31.1787 + }
31.1788 + return captureRemaining;
31.1789 + }
31.1790 +
31.1791 + ko.virtualElements = {
31.1792 + allowedBindings: {},
31.1793 +
31.1794 + childNodes: function(node) {
31.1795 + return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
31.1796 + },
31.1797 +
31.1798 + emptyNode: function(node) {
31.1799 + if (!isStartComment(node))
31.1800 + ko.utils.emptyDomNode(node);
31.1801 + else {
31.1802 + var virtualChildren = ko.virtualElements.childNodes(node);
31.1803 + for (var i = 0, j = virtualChildren.length; i < j; i++)
31.1804 + ko.removeNode(virtualChildren[i]);
31.1805 + }
31.1806 + },
31.1807 +
31.1808 + setDomNodeChildren: function(node, childNodes) {
31.1809 + if (!isStartComment(node))
31.1810 + ko.utils.setDomNodeChildren(node, childNodes);
31.1811 + else {
31.1812 + ko.virtualElements.emptyNode(node);
31.1813 + var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
31.1814 + for (var i = 0, j = childNodes.length; i < j; i++)
31.1815 + endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
31.1816 + }
31.1817 + },
31.1818 +
31.1819 + prepend: function(containerNode, nodeToPrepend) {
31.1820 + if (!isStartComment(containerNode)) {
31.1821 + if (containerNode.firstChild)
31.1822 + containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
31.1823 + else
31.1824 + containerNode.appendChild(nodeToPrepend);
31.1825 + } else {
31.1826 + // Start comments must always have a parent and at least one following sibling (the end comment)
31.1827 + containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
31.1828 + }
31.1829 + },
31.1830 +
31.1831 + insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
31.1832 + if (!insertAfterNode) {
31.1833 + ko.virtualElements.prepend(containerNode, nodeToInsert);
31.1834 + } else if (!isStartComment(containerNode)) {
31.1835 + // Insert after insertion point
31.1836 + if (insertAfterNode.nextSibling)
31.1837 + containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
31.1838 + else
31.1839 + containerNode.appendChild(nodeToInsert);
31.1840 + } else {
31.1841 + // Children of start comments must always have a parent and at least one following sibling (the end comment)
31.1842 + containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
31.1843 + }
31.1844 + },
31.1845 +
31.1846 + firstChild: function(node) {
31.1847 + if (!isStartComment(node))
31.1848 + return node.firstChild;
31.1849 + if (!node.nextSibling || isEndComment(node.nextSibling))
31.1850 + return null;
31.1851 + return node.nextSibling;
31.1852 + },
31.1853 +
31.1854 + nextSibling: function(node) {
31.1855 + if (isStartComment(node))
31.1856 + node = getMatchingEndComment(node);
31.1857 + if (node.nextSibling && isEndComment(node.nextSibling))
31.1858 + return null;
31.1859 + return node.nextSibling;
31.1860 + },
31.1861 +
31.1862 + virtualNodeBindingValue: function(node) {
31.1863 + var regexMatch = isStartComment(node);
31.1864 + return regexMatch ? regexMatch[1] : null;
31.1865 + },
31.1866 +
31.1867 + normaliseVirtualElementDomStructure: function(elementVerified) {
31.1868 + // Workaround for https://github.com/SteveSanderson/knockout/issues/155
31.1869 + // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes
31.1870 + // that are direct descendants of <ul> into the preceding <li>)
31.1871 + if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
31.1872 + return;
31.1873 +
31.1874 + // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
31.1875 + // must be intended to appear *after* that child, so move them there.
31.1876 + var childNode = elementVerified.firstChild;
31.1877 + if (childNode) {
31.1878 + do {
31.1879 + if (childNode.nodeType === 1) {
31.1880 + var unbalancedTags = getUnbalancedChildTags(childNode);
31.1881 + if (unbalancedTags) {
31.1882 + // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
31.1883 + var nodeToInsertBefore = childNode.nextSibling;
31.1884 + for (var i = 0; i < unbalancedTags.length; i++) {
31.1885 + if (nodeToInsertBefore)
31.1886 + elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
31.1887 + else
31.1888 + elementVerified.appendChild(unbalancedTags[i]);
31.1889 + }
31.1890 + }
31.1891 + }
31.1892 + } while (childNode = childNode.nextSibling);
31.1893 + }
31.1894 + }
31.1895 + };
31.1896 +})();
31.1897 +ko.exportSymbol('virtualElements', ko.virtualElements);
31.1898 +ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
31.1899 +ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
31.1900 +//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild); // firstChild is not minified
31.1901 +ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
31.1902 +//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling); // nextSibling is not minified
31.1903 +ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
31.1904 +ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
31.1905 +(function() {
31.1906 + var defaultBindingAttributeName = "data-bind";
31.1907 +
31.1908 + ko.bindingProvider = function() {
31.1909 + this.bindingCache = {};
31.1910 + };
31.1911 +
31.1912 + ko.utils.extend(ko.bindingProvider.prototype, {
31.1913 + 'nodeHasBindings': function(node) {
31.1914 + switch (node.nodeType) {
31.1915 + case 1: return node.getAttribute(defaultBindingAttributeName) != null; // Element
31.1916 + case 8: return ko.virtualElements.virtualNodeBindingValue(node) != null; // Comment node
31.1917 + default: return false;
31.1918 + }
31.1919 + },
31.1920 +
31.1921 + 'getBindings': function(node, bindingContext) {
31.1922 + var bindingsString = this['getBindingsString'](node, bindingContext);
31.1923 + return bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
31.1924 + },
31.1925 +
31.1926 + // The following function is only used internally by this default provider.
31.1927 + // It's not part of the interface definition for a general binding provider.
31.1928 + 'getBindingsString': function(node, bindingContext) {
31.1929 + switch (node.nodeType) {
31.1930 + case 1: return node.getAttribute(defaultBindingAttributeName); // Element
31.1931 + case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
31.1932 + default: return null;
31.1933 + }
31.1934 + },
31.1935 +
31.1936 + // The following function is only used internally by this default provider.
31.1937 + // It's not part of the interface definition for a general binding provider.
31.1938 + 'parseBindingsString': function(bindingsString, bindingContext, node) {
31.1939 + try {
31.1940 + var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache);
31.1941 + return bindingFunction(bindingContext, node);
31.1942 + } catch (ex) {
31.1943 + throw new Error("Unable to parse bindings.\nMessage: " + ex + ";\nBindings value: " + bindingsString);
31.1944 + }
31.1945 + }
31.1946 + });
31.1947 +
31.1948 + ko.bindingProvider['instance'] = new ko.bindingProvider();
31.1949 +
31.1950 + function createBindingsStringEvaluatorViaCache(bindingsString, cache) {
31.1951 + var cacheKey = bindingsString;
31.1952 + return cache[cacheKey]
31.1953 + || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString));
31.1954 + }
31.1955 +
31.1956 + function createBindingsStringEvaluator(bindingsString) {
31.1957 + // Build the source for a function that evaluates "expression"
31.1958 + // For each scope variable, add an extra level of "with" nesting
31.1959 + // Example result: with(sc1) { with(sc0) { return (expression) } }
31.1960 + var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString),
31.1961 + functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
31.1962 + return new Function("$context", "$element", functionBody);
31.1963 + }
31.1964 +})();
31.1965 +
31.1966 +ko.exportSymbol('bindingProvider', ko.bindingProvider);
31.1967 +(function () {
31.1968 + ko.bindingHandlers = {};
31.1969 +
31.1970 + ko.bindingContext = function(dataItem, parentBindingContext, dataItemAlias) {
31.1971 + if (parentBindingContext) {
31.1972 + ko.utils.extend(this, parentBindingContext); // Inherit $root and any custom properties
31.1973 + this['$parentContext'] = parentBindingContext;
31.1974 + this['$parent'] = parentBindingContext['$data'];
31.1975 + this['$parents'] = (parentBindingContext['$parents'] || []).slice(0);
31.1976 + this['$parents'].unshift(this['$parent']);
31.1977 + } else {
31.1978 + this['$parents'] = [];
31.1979 + this['$root'] = dataItem;
31.1980 + // Export 'ko' in the binding context so it will be available in bindings and templates
31.1981 + // even if 'ko' isn't exported as a global, such as when using an AMD loader.
31.1982 + // See https://github.com/SteveSanderson/knockout/issues/490
31.1983 + this['ko'] = ko;
31.1984 + }
31.1985 + this['$data'] = dataItem;
31.1986 + if (dataItemAlias)
31.1987 + this[dataItemAlias] = dataItem;
31.1988 + }
31.1989 + ko.bindingContext.prototype['createChildContext'] = function (dataItem, dataItemAlias) {
31.1990 + return new ko.bindingContext(dataItem, this, dataItemAlias);
31.1991 + };
31.1992 + ko.bindingContext.prototype['extend'] = function(properties) {
31.1993 + var clone = ko.utils.extend(new ko.bindingContext(), this);
31.1994 + return ko.utils.extend(clone, properties);
31.1995 + };
31.1996 +
31.1997 + function validateThatBindingIsAllowedForVirtualElements(bindingName) {
31.1998 + var validator = ko.virtualElements.allowedBindings[bindingName];
31.1999 + if (!validator)
31.2000 + throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
31.2001 + }
31.2002 +
31.2003 + function applyBindingsToDescendantsInternal (viewModel, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
31.2004 + var currentChild, nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
31.2005 + while (currentChild = nextInQueue) {
31.2006 + // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
31.2007 + nextInQueue = ko.virtualElements.nextSibling(currentChild);
31.2008 + applyBindingsToNodeAndDescendantsInternal(viewModel, currentChild, bindingContextsMayDifferFromDomParentElement);
31.2009 + }
31.2010 + }
31.2011 +
31.2012 + function applyBindingsToNodeAndDescendantsInternal (viewModel, nodeVerified, bindingContextMayDifferFromDomParentElement) {
31.2013 + var shouldBindDescendants = true;
31.2014 +
31.2015 + // Perf optimisation: Apply bindings only if...
31.2016 + // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
31.2017 + // Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
31.2018 + // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
31.2019 + var isElement = (nodeVerified.nodeType === 1);
31.2020 + if (isElement) // Workaround IE <= 8 HTML parsing weirdness
31.2021 + ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
31.2022 +
31.2023 + var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement) // Case (1)
31.2024 + || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified); // Case (2)
31.2025 + if (shouldApplyBindings)
31.2026 + shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, viewModel, bindingContextMayDifferFromDomParentElement).shouldBindDescendants;
31.2027 +
31.2028 + if (shouldBindDescendants) {
31.2029 + // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
31.2030 + // * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
31.2031 + // hence bindingContextsMayDifferFromDomParentElement is false
31.2032 + // * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
31.2033 + // skip over any number of intermediate virtual elements, any of which might define a custom binding context,
31.2034 + // hence bindingContextsMayDifferFromDomParentElement is true
31.2035 + applyBindingsToDescendantsInternal(viewModel, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
31.2036 + }
31.2037 + }
31.2038 +
31.2039 + function applyBindingsToNodeInternal (node, bindings, viewModelOrBindingContext, bindingContextMayDifferFromDomParentElement) {
31.2040 + // Need to be sure that inits are only run once, and updates never run until all the inits have been run
31.2041 + var initPhase = 0; // 0 = before all inits, 1 = during inits, 2 = after all inits
31.2042 +
31.2043 + // Each time the dependentObservable is evaluated (after data changes),
31.2044 + // the binding attribute is reparsed so that it can pick out the correct
31.2045 + // model properties in the context of the changed data.
31.2046 + // DOM event callbacks need to be able to access this changed data,
31.2047 + // so we need a single parsedBindings variable (shared by all callbacks
31.2048 + // associated with this node's bindings) that all the closures can access.
31.2049 + var parsedBindings;
31.2050 + function makeValueAccessor(bindingKey) {
31.2051 + return function () { return parsedBindings[bindingKey] }
31.2052 + }
31.2053 + function parsedBindingsAccessor() {
31.2054 + return parsedBindings;
31.2055 + }
31.2056 +
31.2057 + var bindingHandlerThatControlsDescendantBindings;
31.2058 + ko.dependentObservable(
31.2059 + function () {
31.2060 + // Ensure we have a nonnull binding context to work with
31.2061 + var bindingContextInstance = viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
31.2062 + ? viewModelOrBindingContext
31.2063 + : new ko.bindingContext(ko.utils.unwrapObservable(viewModelOrBindingContext));
31.2064 + var viewModel = bindingContextInstance['$data'];
31.2065 +
31.2066 + // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
31.2067 + // we can easily recover it just by scanning up the node's ancestors in the DOM
31.2068 + // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
31.2069 + if (bindingContextMayDifferFromDomParentElement)
31.2070 + ko.storedBindingContextForNode(node, bindingContextInstance);
31.2071 +
31.2072 + // Use evaluatedBindings if given, otherwise fall back on asking the bindings provider to give us some bindings
31.2073 + var evaluatedBindings = (typeof bindings == "function") ? bindings(bindingContextInstance, node) : bindings;
31.2074 + parsedBindings = evaluatedBindings || ko.bindingProvider['instance']['getBindings'](node, bindingContextInstance);
31.2075 +
31.2076 + if (parsedBindings) {
31.2077 + // First run all the inits, so bindings can register for notification on changes
31.2078 + if (initPhase === 0) {
31.2079 + initPhase = 1;
31.2080 + for (var bindingKey in parsedBindings) {
31.2081 + var binding = ko.bindingHandlers[bindingKey];
31.2082 + if (binding && node.nodeType === 8)
31.2083 + validateThatBindingIsAllowedForVirtualElements(bindingKey);
31.2084 +
31.2085 + if (binding && typeof binding["init"] == "function") {
31.2086 + var handlerInitFn = binding["init"];
31.2087 + var initResult = handlerInitFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
31.2088 +
31.2089 + // If this binding handler claims to control descendant bindings, make a note of this
31.2090 + if (initResult && initResult['controlsDescendantBindings']) {
31.2091 + if (bindingHandlerThatControlsDescendantBindings !== undefined)
31.2092 + throw new Error("Multiple bindings (" + bindingHandlerThatControlsDescendantBindings + " and " + bindingKey + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
31.2093 + bindingHandlerThatControlsDescendantBindings = bindingKey;
31.2094 + }
31.2095 + }
31.2096 + }
31.2097 + initPhase = 2;
31.2098 + }
31.2099 +
31.2100 + // ... then run all the updates, which might trigger changes even on the first evaluation
31.2101 + if (initPhase === 2) {
31.2102 + for (var bindingKey in parsedBindings) {
31.2103 + var binding = ko.bindingHandlers[bindingKey];
31.2104 + if (binding && typeof binding["update"] == "function") {
31.2105 + var handlerUpdateFn = binding["update"];
31.2106 + handlerUpdateFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
31.2107 + }
31.2108 + }
31.2109 + }
31.2110 + }
31.2111 + },
31.2112 + null,
31.2113 + { disposeWhenNodeIsRemoved : node }
31.2114 + );
31.2115 +
31.2116 + return {
31.2117 + shouldBindDescendants: bindingHandlerThatControlsDescendantBindings === undefined
31.2118 + };
31.2119 + };
31.2120 +
31.2121 + var storedBindingContextDomDataKey = "__ko_bindingContext__";
31.2122 + ko.storedBindingContextForNode = function (node, bindingContext) {
31.2123 + if (arguments.length == 2)
31.2124 + ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
31.2125 + else
31.2126 + return ko.utils.domData.get(node, storedBindingContextDomDataKey);
31.2127 + }
31.2128 +
31.2129 + ko.applyBindingsToNode = function (node, bindings, viewModel) {
31.2130 + if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
31.2131 + ko.virtualElements.normaliseVirtualElementDomStructure(node);
31.2132 + return applyBindingsToNodeInternal(node, bindings, viewModel, true);
31.2133 + };
31.2134 +
31.2135 + ko.applyBindingsToDescendants = function(viewModel, rootNode) {
31.2136 + if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
31.2137 + applyBindingsToDescendantsInternal(viewModel, rootNode, true);
31.2138 + };
31.2139 +
31.2140 + ko.applyBindings = function (viewModel, rootNode) {
31.2141 + if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
31.2142 + throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
31.2143 + rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
31.2144 +
31.2145 + applyBindingsToNodeAndDescendantsInternal(viewModel, rootNode, true);
31.2146 + };
31.2147 +
31.2148 + // Retrieving binding context from arbitrary nodes
31.2149 + ko.contextFor = function(node) {
31.2150 + // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
31.2151 + switch (node.nodeType) {
31.2152 + case 1:
31.2153 + case 8:
31.2154 + var context = ko.storedBindingContextForNode(node);
31.2155 + if (context) return context;
31.2156 + if (node.parentNode) return ko.contextFor(node.parentNode);
31.2157 + break;
31.2158 + }
31.2159 + return undefined;
31.2160 + };
31.2161 + ko.dataFor = function(node) {
31.2162 + var context = ko.contextFor(node);
31.2163 + return context ? context['$data'] : undefined;
31.2164 + };
31.2165 +
31.2166 + ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
31.2167 + ko.exportSymbol('applyBindings', ko.applyBindings);
31.2168 + ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
31.2169 + ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
31.2170 + ko.exportSymbol('contextFor', ko.contextFor);
31.2171 + ko.exportSymbol('dataFor', ko.dataFor);
31.2172 +})();
31.2173 +var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
31.2174 +ko.bindingHandlers['attr'] = {
31.2175 + 'update': function(element, valueAccessor, allBindingsAccessor) {
31.2176 + var value = ko.utils.unwrapObservable(valueAccessor()) || {};
31.2177 + for (var attrName in value) {
31.2178 + if (typeof attrName == "string") {
31.2179 + var attrValue = ko.utils.unwrapObservable(value[attrName]);
31.2180 +
31.2181 + // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
31.2182 + // when someProp is a "no value"-like value (strictly null, false, or undefined)
31.2183 + // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
31.2184 + var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
31.2185 + if (toRemove)
31.2186 + element.removeAttribute(attrName);
31.2187 +
31.2188 + // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
31.2189 + // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
31.2190 + // but instead of figuring out the mode, we'll just set the attribute through the Javascript
31.2191 + // property for IE <= 8.
31.2192 + if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
31.2193 + attrName = attrHtmlToJavascriptMap[attrName];
31.2194 + if (toRemove)
31.2195 + element.removeAttribute(attrName);
31.2196 + else
31.2197 + element[attrName] = attrValue;
31.2198 + } else if (!toRemove) {
31.2199 + element.setAttribute(attrName, attrValue.toString());
31.2200 + }
31.2201 +
31.2202 + // Treat "name" specially - although you can think of it as an attribute, it also needs
31.2203 + // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
31.2204 + // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
31.2205 + // entirely, and there's no strong reason to allow for such casing in HTML.
31.2206 + if (attrName === "name") {
31.2207 + ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
31.2208 + }
31.2209 + }
31.2210 + }
31.2211 + }
31.2212 +};
31.2213 +ko.bindingHandlers['checked'] = {
31.2214 + 'init': function (element, valueAccessor, allBindingsAccessor) {
31.2215 + var updateHandler = function() {
31.2216 + var valueToWrite;
31.2217 + if (element.type == "checkbox") {
31.2218 + valueToWrite = element.checked;
31.2219 + } else if ((element.type == "radio") && (element.checked)) {
31.2220 + valueToWrite = element.value;
31.2221 + } else {
31.2222 + return; // "checked" binding only responds to checkboxes and selected radio buttons
31.2223 + }
31.2224 +
31.2225 + var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue);
31.2226 + if ((element.type == "checkbox") && (unwrappedValue instanceof Array)) {
31.2227 + // For checkboxes bound to an array, we add/remove the checkbox value to that array
31.2228 + // This works for both observable and non-observable arrays
31.2229 + var existingEntryIndex = ko.utils.arrayIndexOf(unwrappedValue, element.value);
31.2230 + if (element.checked && (existingEntryIndex < 0))
31.2231 + modelValue.push(element.value);
31.2232 + else if ((!element.checked) && (existingEntryIndex >= 0))
31.2233 + modelValue.splice(existingEntryIndex, 1);
31.2234 + } else {
31.2235 + ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
31.2236 + }
31.2237 + };
31.2238 + ko.utils.registerEventHandler(element, "click", updateHandler);
31.2239 +
31.2240 + // IE 6 won't allow radio buttons to be selected unless they have a name
31.2241 + if ((element.type == "radio") && !element.name)
31.2242 + ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
31.2243 + },
31.2244 + 'update': function (element, valueAccessor) {
31.2245 + var value = ko.utils.unwrapObservable(valueAccessor());
31.2246 +
31.2247 + if (element.type == "checkbox") {
31.2248 + if (value instanceof Array) {
31.2249 + // When bound to an array, the checkbox being checked represents its value being present in that array
31.2250 + element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
31.2251 + } else {
31.2252 + // When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
31.2253 + element.checked = value;
31.2254 + }
31.2255 + } else if (element.type == "radio") {
31.2256 + element.checked = (element.value == value);
31.2257 + }
31.2258 + }
31.2259 +};
31.2260 +var classesWrittenByBindingKey = '__ko__cssValue';
31.2261 +ko.bindingHandlers['css'] = {
31.2262 + 'update': function (element, valueAccessor) {
31.2263 + var value = ko.utils.unwrapObservable(valueAccessor());
31.2264 + if (typeof value == "object") {
31.2265 + for (var className in value) {
31.2266 + var shouldHaveClass = ko.utils.unwrapObservable(value[className]);
31.2267 + ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
31.2268 + }
31.2269 + } else {
31.2270 + value = String(value || ''); // Make sure we don't try to store or set a non-string value
31.2271 + ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
31.2272 + element[classesWrittenByBindingKey] = value;
31.2273 + ko.utils.toggleDomNodeCssClass(element, value, true);
31.2274 + }
31.2275 + }
31.2276 +};
31.2277 +ko.bindingHandlers['enable'] = {
31.2278 + 'update': function (element, valueAccessor) {
31.2279 + var value = ko.utils.unwrapObservable(valueAccessor());
31.2280 + if (value && element.disabled)
31.2281 + element.removeAttribute("disabled");
31.2282 + else if ((!value) && (!element.disabled))
31.2283 + element.disabled = true;
31.2284 + }
31.2285 +};
31.2286 +
31.2287 +ko.bindingHandlers['disable'] = {
31.2288 + 'update': function (element, valueAccessor) {
31.2289 + ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
31.2290 + }
31.2291 +};
31.2292 +// For certain common events (currently just 'click'), allow a simplified data-binding syntax
31.2293 +// e.g. click:handler instead of the usual full-length event:{click:handler}
31.2294 +function makeEventHandlerShortcut(eventName) {
31.2295 + ko.bindingHandlers[eventName] = {
31.2296 + 'init': function(element, valueAccessor, allBindingsAccessor, viewModel) {
31.2297 + var newValueAccessor = function () {
31.2298 + var result = {};
31.2299 + result[eventName] = valueAccessor();
31.2300 + return result;
31.2301 + };
31.2302 + return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindingsAccessor, viewModel);
31.2303 + }
31.2304 + }
31.2305 +}
31.2306 +
31.2307 +ko.bindingHandlers['event'] = {
31.2308 + 'init' : function (element, valueAccessor, allBindingsAccessor, viewModel) {
31.2309 + var eventsToHandle = valueAccessor() || {};
31.2310 + for(var eventNameOutsideClosure in eventsToHandle) {
31.2311 + (function() {
31.2312 + var eventName = eventNameOutsideClosure; // Separate variable to be captured by event handler closure
31.2313 + if (typeof eventName == "string") {
31.2314 + ko.utils.registerEventHandler(element, eventName, function (event) {
31.2315 + var handlerReturnValue;
31.2316 + var handlerFunction = valueAccessor()[eventName];
31.2317 + if (!handlerFunction)
31.2318 + return;
31.2319 + var allBindings = allBindingsAccessor();
31.2320 +
31.2321 + try {
31.2322 + // Take all the event args, and prefix with the viewmodel
31.2323 + var argsForHandler = ko.utils.makeArray(arguments);
31.2324 + argsForHandler.unshift(viewModel);
31.2325 + handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
31.2326 + } finally {
31.2327 + if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
31.2328 + if (event.preventDefault)
31.2329 + event.preventDefault();
31.2330 + else
31.2331 + event.returnValue = false;
31.2332 + }
31.2333 + }
31.2334 +
31.2335 + var bubble = allBindings[eventName + 'Bubble'] !== false;
31.2336 + if (!bubble) {
31.2337 + event.cancelBubble = true;
31.2338 + if (event.stopPropagation)
31.2339 + event.stopPropagation();
31.2340 + }
31.2341 + });
31.2342 + }
31.2343 + })();
31.2344 + }
31.2345 + }
31.2346 +};
31.2347 +// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
31.2348 +// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
31.2349 +ko.bindingHandlers['foreach'] = {
31.2350 + makeTemplateValueAccessor: function(valueAccessor) {
31.2351 + return function() {
31.2352 + var modelValue = valueAccessor(),
31.2353 + unwrappedValue = ko.utils.peekObservable(modelValue); // Unwrap without setting a dependency here
31.2354 +
31.2355 + // If unwrappedValue is the array, pass in the wrapped value on its own
31.2356 + // The value will be unwrapped and tracked within the template binding
31.2357 + // (See https://github.com/SteveSanderson/knockout/issues/523)
31.2358 + if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
31.2359 + return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
31.2360 +
31.2361 + // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
31.2362 + ko.utils.unwrapObservable(modelValue);
31.2363 + return {
31.2364 + 'foreach': unwrappedValue['data'],
31.2365 + 'as': unwrappedValue['as'],
31.2366 + 'includeDestroyed': unwrappedValue['includeDestroyed'],
31.2367 + 'afterAdd': unwrappedValue['afterAdd'],
31.2368 + 'beforeRemove': unwrappedValue['beforeRemove'],
31.2369 + 'afterRender': unwrappedValue['afterRender'],
31.2370 + 'beforeMove': unwrappedValue['beforeMove'],
31.2371 + 'afterMove': unwrappedValue['afterMove'],
31.2372 + 'templateEngine': ko.nativeTemplateEngine.instance
31.2373 + };
31.2374 + };
31.2375 + },
31.2376 + 'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
31.2377 + return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
31.2378 + },
31.2379 + 'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
31.2380 + return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindingsAccessor, viewModel, bindingContext);
31.2381 + }
31.2382 +};
31.2383 +ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
31.2384 +ko.virtualElements.allowedBindings['foreach'] = true;
31.2385 +var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
31.2386 +ko.bindingHandlers['hasfocus'] = {
31.2387 + 'init': function(element, valueAccessor, allBindingsAccessor) {
31.2388 + var handleElementFocusChange = function(isFocused) {
31.2389 + // Where possible, ignore which event was raised and determine focus state using activeElement,
31.2390 + // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
31.2391 + // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
31.2392 + // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
31.2393 + // from calling 'blur()' on the element when it loses focus.
31.2394 + // Discussion at https://github.com/SteveSanderson/knockout/pull/352
31.2395 + element[hasfocusUpdatingProperty] = true;
31.2396 + var ownerDoc = element.ownerDocument;
31.2397 + if ("activeElement" in ownerDoc) {
31.2398 + isFocused = (ownerDoc.activeElement === element);
31.2399 + }
31.2400 + var modelValue = valueAccessor();
31.2401 + ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'hasfocus', isFocused, true);
31.2402 + element[hasfocusUpdatingProperty] = false;
31.2403 + };
31.2404 + var handleElementFocusIn = handleElementFocusChange.bind(null, true);
31.2405 + var handleElementFocusOut = handleElementFocusChange.bind(null, false);
31.2406 +
31.2407 + ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
31.2408 + ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
31.2409 + ko.utils.registerEventHandler(element, "blur", handleElementFocusOut);
31.2410 + ko.utils.registerEventHandler(element, "focusout", handleElementFocusOut); // For IE
31.2411 + },
31.2412 + 'update': function(element, valueAccessor) {
31.2413 + var value = ko.utils.unwrapObservable(valueAccessor());
31.2414 + if (!element[hasfocusUpdatingProperty]) {
31.2415 + value ? element.focus() : element.blur();
31.2416 + ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
31.2417 + }
31.2418 + }
31.2419 +};
31.2420 +ko.bindingHandlers['html'] = {
31.2421 + 'init': function() {
31.2422 + // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
31.2423 + return { 'controlsDescendantBindings': true };
31.2424 + },
31.2425 + 'update': function (element, valueAccessor) {
31.2426 + // setHtml will unwrap the value if needed
31.2427 + ko.utils.setHtml(element, valueAccessor());
31.2428 + }
31.2429 +};
31.2430 +var withIfDomDataKey = '__ko_withIfBindingData';
31.2431 +// Makes a binding like with or if
31.2432 +function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
31.2433 + ko.bindingHandlers[bindingKey] = {
31.2434 + 'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
31.2435 + ko.utils.domData.set(element, withIfDomDataKey, {});
31.2436 + return { 'controlsDescendantBindings': true };
31.2437 + },
31.2438 + 'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
31.2439 + var withIfData = ko.utils.domData.get(element, withIfDomDataKey),
31.2440 + dataValue = ko.utils.unwrapObservable(valueAccessor()),
31.2441 + shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
31.2442 + isFirstRender = !withIfData.savedNodes,
31.2443 + needsRefresh = isFirstRender || isWith || (shouldDisplay !== withIfData.didDisplayOnLastUpdate);
31.2444 +
31.2445 + if (needsRefresh) {
31.2446 + if (isFirstRender) {
31.2447 + withIfData.savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
31.2448 + }
31.2449 +
31.2450 + if (shouldDisplay) {
31.2451 + if (!isFirstRender) {
31.2452 + ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(withIfData.savedNodes));
31.2453 + }
31.2454 + ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
31.2455 + } else {
31.2456 + ko.virtualElements.emptyNode(element);
31.2457 + }
31.2458 +
31.2459 + withIfData.didDisplayOnLastUpdate = shouldDisplay;
31.2460 + }
31.2461 + }
31.2462 + };
31.2463 + ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
31.2464 + ko.virtualElements.allowedBindings[bindingKey] = true;
31.2465 +}
31.2466 +
31.2467 +// Construct the actual binding handlers
31.2468 +makeWithIfBinding('if');
31.2469 +makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
31.2470 +makeWithIfBinding('with', true /* isWith */, false /* isNot */,
31.2471 + function(bindingContext, dataValue) {
31.2472 + return bindingContext['createChildContext'](dataValue);
31.2473 + }
31.2474 +);
31.2475 +function ensureDropdownSelectionIsConsistentWithModelValue(element, modelValue, preferModelValue) {
31.2476 + if (preferModelValue) {
31.2477 + if (modelValue !== ko.selectExtensions.readValue(element))
31.2478 + ko.selectExtensions.writeValue(element, modelValue);
31.2479 + }
31.2480 +
31.2481 + // No matter which direction we're syncing in, we want the end result to be equality between dropdown value and model value.
31.2482 + // If they aren't equal, either we prefer the dropdown value, or the model value couldn't be represented, so either way,
31.2483 + // change the model value to match the dropdown.
31.2484 + if (modelValue !== ko.selectExtensions.readValue(element))
31.2485 + ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
31.2486 +};
31.2487 +
31.2488 +ko.bindingHandlers['options'] = {
31.2489 + 'update': function (element, valueAccessor, allBindingsAccessor) {
31.2490 + if (ko.utils.tagNameLower(element) !== "select")
31.2491 + throw new Error("options binding applies only to SELECT elements");
31.2492 +
31.2493 + var selectWasPreviouslyEmpty = element.length == 0;
31.2494 + var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
31.2495 + return node.tagName && (ko.utils.tagNameLower(node) === "option") && node.selected;
31.2496 + }), function (node) {
31.2497 + return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
31.2498 + });
31.2499 + var previousScrollTop = element.scrollTop;
31.2500 +
31.2501 + var value = ko.utils.unwrapObservable(valueAccessor());
31.2502 + var selectedValue = element.value;
31.2503 +
31.2504 + // Remove all existing <option>s.
31.2505 + // Need to use .remove() rather than .removeChild() for <option>s otherwise IE behaves oddly (https://github.com/SteveSanderson/knockout/issues/134)
31.2506 + while (element.length > 0) {
31.2507 + ko.cleanNode(element.options[0]);
31.2508 + element.remove(0);
31.2509 + }
31.2510 +
31.2511 + if (value) {
31.2512 + var allBindings = allBindingsAccessor(),
31.2513 + includeDestroyed = allBindings['optionsIncludeDestroyed'];
31.2514 +
31.2515 + if (typeof value.length != "number")
31.2516 + value = [value];
31.2517 + if (allBindings['optionsCaption']) {
31.2518 + var option = document.createElement("option");
31.2519 + ko.utils.setHtml(option, allBindings['optionsCaption']);
31.2520 + ko.selectExtensions.writeValue(option, undefined);
31.2521 + element.appendChild(option);
31.2522 + }
31.2523 +
31.2524 + for (var i = 0, j = value.length; i < j; i++) {
31.2525 + // Skip destroyed items
31.2526 + var arrayEntry = value[i];
31.2527 + if (arrayEntry && arrayEntry['_destroy'] && !includeDestroyed)
31.2528 + continue;
31.2529 +
31.2530 + var option = document.createElement("option");
31.2531 +
31.2532 + function applyToObject(object, predicate, defaultValue) {
31.2533 + var predicateType = typeof predicate;
31.2534 + if (predicateType == "function") // Given a function; run it against the data value
31.2535 + return predicate(object);
31.2536 + else if (predicateType == "string") // Given a string; treat it as a property name on the data value
31.2537 + return object[predicate];
31.2538 + else // Given no optionsText arg; use the data value itself
31.2539 + return defaultValue;
31.2540 + }
31.2541 +
31.2542 + // Apply a value to the option element
31.2543 + var optionValue = applyToObject(arrayEntry, allBindings['optionsValue'], arrayEntry);
31.2544 + ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
31.2545 +
31.2546 + // Apply some text to the option element
31.2547 + var optionText = applyToObject(arrayEntry, allBindings['optionsText'], optionValue);
31.2548 + ko.utils.setTextContent(option, optionText);
31.2549 +
31.2550 + element.appendChild(option);
31.2551 + }
31.2552 +
31.2553 + // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
31.2554 + // That's why we first added them without selection. Now it's time to set the selection.
31.2555 + var newOptions = element.getElementsByTagName("option");
31.2556 + var countSelectionsRetained = 0;
31.2557 + for (var i = 0, j = newOptions.length; i < j; i++) {
31.2558 + if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) {
31.2559 + ko.utils.setOptionNodeSelectionState(newOptions[i], true);
31.2560 + countSelectionsRetained++;
31.2561 + }
31.2562 + }
31.2563 +
31.2564 + element.scrollTop = previousScrollTop;
31.2565 +
31.2566 + if (selectWasPreviouslyEmpty && ('value' in allBindings)) {
31.2567 + // Ensure consistency between model value and selected option.
31.2568 + // If the dropdown is being populated for the first time here (or was otherwise previously empty),
31.2569 + // the dropdown selection state is meaningless, so we preserve the model value.
31.2570 + ensureDropdownSelectionIsConsistentWithModelValue(element, ko.utils.peekObservable(allBindings['value']), /* preferModelValue */ true);
31.2571 + }
31.2572 +
31.2573 + // Workaround for IE9 bug
31.2574 + ko.utils.ensureSelectElementIsRenderedCorrectly(element);
31.2575 + }
31.2576 + }
31.2577 +};
31.2578 +ko.bindingHandlers['options'].optionValueDomDataKey = '__ko.optionValueDomData__';
31.2579 +ko.bindingHandlers['selectedOptions'] = {
31.2580 + 'init': function (element, valueAccessor, allBindingsAccessor) {
31.2581 + ko.utils.registerEventHandler(element, "change", function () {
31.2582 + var value = valueAccessor(), valueToWrite = [];
31.2583 + ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
31.2584 + if (node.selected)
31.2585 + valueToWrite.push(ko.selectExtensions.readValue(node));
31.2586 + });
31.2587 + ko.expressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite);
31.2588 + });
31.2589 + },
31.2590 + 'update': function (element, valueAccessor) {
31.2591 + if (ko.utils.tagNameLower(element) != "select")
31.2592 + throw new Error("values binding applies only to SELECT elements");
31.2593 +
31.2594 + var newValue = ko.utils.unwrapObservable(valueAccessor());
31.2595 + if (newValue && typeof newValue.length == "number") {
31.2596 + ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
31.2597 + var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
31.2598 + ko.utils.setOptionNodeSelectionState(node, isSelected);
31.2599 + });
31.2600 + }
31.2601 + }
31.2602 +};
31.2603 +ko.bindingHandlers['style'] = {
31.2604 + 'update': function (element, valueAccessor) {
31.2605 + var value = ko.utils.unwrapObservable(valueAccessor() || {});
31.2606 + for (var styleName in value) {
31.2607 + if (typeof styleName == "string") {
31.2608 + var styleValue = ko.utils.unwrapObservable(value[styleName]);
31.2609 + element.style[styleName] = styleValue || ""; // Empty string removes the value, whereas null/undefined have no effect
31.2610 + }
31.2611 + }
31.2612 + }
31.2613 +};
31.2614 +ko.bindingHandlers['submit'] = {
31.2615 + 'init': function (element, valueAccessor, allBindingsAccessor, viewModel) {
31.2616 + if (typeof valueAccessor() != "function")
31.2617 + throw new Error("The value for a submit binding must be a function");
31.2618 + ko.utils.registerEventHandler(element, "submit", function (event) {
31.2619 + var handlerReturnValue;
31.2620 + var value = valueAccessor();
31.2621 + try { handlerReturnValue = value.call(viewModel, element); }
31.2622 + finally {
31.2623 + if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
31.2624 + if (event.preventDefault)
31.2625 + event.preventDefault();
31.2626 + else
31.2627 + event.returnValue = false;
31.2628 + }
31.2629 + }
31.2630 + });
31.2631 + }
31.2632 +};
31.2633 +ko.bindingHandlers['text'] = {
31.2634 + 'update': function (element, valueAccessor) {
31.2635 + ko.utils.setTextContent(element, valueAccessor());
31.2636 + }
31.2637 +};
31.2638 +ko.virtualElements.allowedBindings['text'] = true;
31.2639 +ko.bindingHandlers['uniqueName'] = {
31.2640 + 'init': function (element, valueAccessor) {
31.2641 + if (valueAccessor()) {
31.2642 + var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
31.2643 + ko.utils.setElementName(element, name);
31.2644 + }
31.2645 + }
31.2646 +};
31.2647 +ko.bindingHandlers['uniqueName'].currentIndex = 0;
31.2648 +ko.bindingHandlers['value'] = {
31.2649 + 'init': function (element, valueAccessor, allBindingsAccessor) {
31.2650 + // Always catch "change" event; possibly other events too if asked
31.2651 + var eventsToCatch = ["change"];
31.2652 + var requestedEventsToCatch = allBindingsAccessor()["valueUpdate"];
31.2653 + var propertyChangedFired = false;
31.2654 + if (requestedEventsToCatch) {
31.2655 + if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
31.2656 + requestedEventsToCatch = [requestedEventsToCatch];
31.2657 + ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
31.2658 + eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
31.2659 + }
31.2660 +
31.2661 + var valueUpdateHandler = function() {
31.2662 + propertyChangedFired = false;
31.2663 + var modelValue = valueAccessor();
31.2664 + var elementValue = ko.selectExtensions.readValue(element);
31.2665 + ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'value', elementValue);
31.2666 + }
31.2667 +
31.2668 + // Workaround for https://github.com/SteveSanderson/knockout/issues/122
31.2669 + // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
31.2670 + var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
31.2671 + && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
31.2672 + if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
31.2673 + ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
31.2674 + ko.utils.registerEventHandler(element, "blur", function() {
31.2675 + if (propertyChangedFired) {
31.2676 + valueUpdateHandler();
31.2677 + }
31.2678 + });
31.2679 + }
31.2680 +
31.2681 + ko.utils.arrayForEach(eventsToCatch, function(eventName) {
31.2682 + // The syntax "after<eventname>" means "run the handler asynchronously after the event"
31.2683 + // This is useful, for example, to catch "keydown" events after the browser has updated the control
31.2684 + // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
31.2685 + var handler = valueUpdateHandler;
31.2686 + if (ko.utils.stringStartsWith(eventName, "after")) {
31.2687 + handler = function() { setTimeout(valueUpdateHandler, 0) };
31.2688 + eventName = eventName.substring("after".length);
31.2689 + }
31.2690 + ko.utils.registerEventHandler(element, eventName, handler);
31.2691 + });
31.2692 + },
31.2693 + 'update': function (element, valueAccessor) {
31.2694 + var valueIsSelectOption = ko.utils.tagNameLower(element) === "select";
31.2695 + var newValue = ko.utils.unwrapObservable(valueAccessor());
31.2696 + var elementValue = ko.selectExtensions.readValue(element);
31.2697 + var valueHasChanged = (newValue != elementValue);
31.2698 +
31.2699 + // JavaScript's 0 == "" behavious is unfortunate here as it prevents writing 0 to an empty text box (loose equality suggests the values are the same).
31.2700 + // We don't want to do a strict equality comparison as that is more confusing for developers in certain cases, so we specifically special case 0 != "" here.
31.2701 + if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0"))
31.2702 + valueHasChanged = true;
31.2703 +
31.2704 + if (valueHasChanged) {
31.2705 + var applyValueAction = function () { ko.selectExtensions.writeValue(element, newValue); };
31.2706 + applyValueAction();
31.2707 +
31.2708 + // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
31.2709 + // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
31.2710 + // to apply the value as well.
31.2711 + var alsoApplyAsynchronously = valueIsSelectOption;
31.2712 + if (alsoApplyAsynchronously)
31.2713 + setTimeout(applyValueAction, 0);
31.2714 + }
31.2715 +
31.2716 + // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
31.2717 + // because you're not allowed to have a model value that disagrees with a visible UI selection.
31.2718 + if (valueIsSelectOption && (element.length > 0))
31.2719 + ensureDropdownSelectionIsConsistentWithModelValue(element, newValue, /* preferModelValue */ false);
31.2720 + }
31.2721 +};
31.2722 +ko.bindingHandlers['visible'] = {
31.2723 + 'update': function (element, valueAccessor) {
31.2724 + var value = ko.utils.unwrapObservable(valueAccessor());
31.2725 + var isCurrentlyVisible = !(element.style.display == "none");
31.2726 + if (value && !isCurrentlyVisible)
31.2727 + element.style.display = "";
31.2728 + else if ((!value) && isCurrentlyVisible)
31.2729 + element.style.display = "none";
31.2730 + }
31.2731 +};
31.2732 +// 'click' is just a shorthand for the usual full-length event:{click:handler}
31.2733 +makeEventHandlerShortcut('click');
31.2734 +// If you want to make a custom template engine,
31.2735 +//
31.2736 +// [1] Inherit from this class (like ko.nativeTemplateEngine does)
31.2737 +// [2] Override 'renderTemplateSource', supplying a function with this signature:
31.2738 +//
31.2739 +// function (templateSource, bindingContext, options) {
31.2740 +// // - templateSource.text() is the text of the template you should render
31.2741 +// // - bindingContext.$data is the data you should pass into the template
31.2742 +// // - you might also want to make bindingContext.$parent, bindingContext.$parents,
31.2743 +// // and bindingContext.$root available in the template too
31.2744 +// // - options gives you access to any other properties set on "data-bind: { template: options }"
31.2745 +// //
31.2746 +// // Return value: an array of DOM nodes
31.2747 +// }
31.2748 +//
31.2749 +// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
31.2750 +//
31.2751 +// function (script) {
31.2752 +// // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
31.2753 +// // For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
31.2754 +// }
31.2755 +//
31.2756 +// This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
31.2757 +// If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
31.2758 +// and then you don't need to override 'createJavaScriptEvaluatorBlock'.
31.2759 +
31.2760 +ko.templateEngine = function () { };
31.2761 +
31.2762 +ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
31.2763 + throw new Error("Override renderTemplateSource");
31.2764 +};
31.2765 +
31.2766 +ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
31.2767 + throw new Error("Override createJavaScriptEvaluatorBlock");
31.2768 +};
31.2769 +
31.2770 +ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
31.2771 + // Named template
31.2772 + if (typeof template == "string") {
31.2773 + templateDocument = templateDocument || document;
31.2774 + var elem = templateDocument.getElementById(template);
31.2775 + if (!elem)
31.2776 + throw new Error("Cannot find template with ID " + template);
31.2777 + return new ko.templateSources.domElement(elem);
31.2778 + } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
31.2779 + // Anonymous template
31.2780 + return new ko.templateSources.anonymousTemplate(template);
31.2781 + } else
31.2782 + throw new Error("Unknown template type: " + template);
31.2783 +};
31.2784 +
31.2785 +ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
31.2786 + var templateSource = this['makeTemplateSource'](template, templateDocument);
31.2787 + return this['renderTemplateSource'](templateSource, bindingContext, options);
31.2788 +};
31.2789 +
31.2790 +ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
31.2791 + // Skip rewriting if requested
31.2792 + if (this['allowTemplateRewriting'] === false)
31.2793 + return true;
31.2794 + return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
31.2795 +};
31.2796 +
31.2797 +ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
31.2798 + var templateSource = this['makeTemplateSource'](template, templateDocument);
31.2799 + var rewritten = rewriterCallback(templateSource['text']());
31.2800 + templateSource['text'](rewritten);
31.2801 + templateSource['data']("isRewritten", true);
31.2802 +};
31.2803 +
31.2804 +ko.exportSymbol('templateEngine', ko.templateEngine);
31.2805 +
31.2806 +ko.templateRewriting = (function () {
31.2807 + var memoizeDataBindingAttributeSyntaxRegex = /(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi;
31.2808 + var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
31.2809 +
31.2810 + function validateDataBindValuesForRewriting(keyValueArray) {
31.2811 + var allValidators = ko.expressionRewriting.bindingRewriteValidators;
31.2812 + for (var i = 0; i < keyValueArray.length; i++) {
31.2813 + var key = keyValueArray[i]['key'];
31.2814 + if (allValidators.hasOwnProperty(key)) {
31.2815 + var validator = allValidators[key];
31.2816 +
31.2817 + if (typeof validator === "function") {
31.2818 + var possibleErrorMessage = validator(keyValueArray[i]['value']);
31.2819 + if (possibleErrorMessage)
31.2820 + throw new Error(possibleErrorMessage);
31.2821 + } else if (!validator) {
31.2822 + throw new Error("This template engine does not support the '" + key + "' binding within its templates");
31.2823 + }
31.2824 + }
31.2825 + }
31.2826 + }
31.2827 +
31.2828 + function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, templateEngine) {
31.2829 + var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
31.2830 + validateDataBindValuesForRewriting(dataBindKeyValueArray);
31.2831 + var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray);
31.2832 +
31.2833 + // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
31.2834 + // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
31.2835 + // extra indirection.
31.2836 + var applyBindingsToNextSiblingScript =
31.2837 + "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()})";
31.2838 + return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
31.2839 + }
31.2840 +
31.2841 + return {
31.2842 + ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
31.2843 + if (!templateEngine['isTemplateRewritten'](template, templateDocument))
31.2844 + templateEngine['rewriteTemplate'](template, function (htmlString) {
31.2845 + return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
31.2846 + }, templateDocument);
31.2847 + },
31.2848 +
31.2849 + memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
31.2850 + return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
31.2851 + return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[6], /* tagToRetain: */ arguments[1], templateEngine);
31.2852 + }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
31.2853 + return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", templateEngine);
31.2854 + });
31.2855 + },
31.2856 +
31.2857 + applyMemoizedBindingsToNextSibling: function (bindings) {
31.2858 + return ko.memoization.memoize(function (domNode, bindingContext) {
31.2859 + if (domNode.nextSibling)
31.2860 + ko.applyBindingsToNode(domNode.nextSibling, bindings, bindingContext);
31.2861 + });
31.2862 + }
31.2863 + }
31.2864 +})();
31.2865 +
31.2866 +
31.2867 +// Exported only because it has to be referenced by string lookup from within rewritten template
31.2868 +ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
31.2869 +(function() {
31.2870 + // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
31.2871 + // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
31.2872 + //
31.2873 + // Two are provided by default:
31.2874 + // 1. ko.templateSources.domElement - reads/writes the text content of an arbitrary DOM element
31.2875 + // 2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
31.2876 + // without reading/writing the actual element text content, since it will be overwritten
31.2877 + // with the rendered template output.
31.2878 + // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
31.2879 + // Template sources need to have the following functions:
31.2880 + // text() - returns the template text from your storage location
31.2881 + // text(value) - writes the supplied template text to your storage location
31.2882 + // data(key) - reads values stored using data(key, value) - see below
31.2883 + // data(key, value) - associates "value" with this template and the key "key". Is used to store information like "isRewritten".
31.2884 + //
31.2885 + // Optionally, template sources can also have the following functions:
31.2886 + // nodes() - returns a DOM element containing the nodes of this template, where available
31.2887 + // nodes(value) - writes the given DOM element to your storage location
31.2888 + // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
31.2889 + // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
31.2890 + //
31.2891 + // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
31.2892 + // using and overriding "makeTemplateSource" to return an instance of your custom template source.
31.2893 +
31.2894 + ko.templateSources = {};
31.2895 +
31.2896 + // ---- ko.templateSources.domElement -----
31.2897 +
31.2898 + ko.templateSources.domElement = function(element) {
31.2899 + this.domElement = element;
31.2900 + }
31.2901 +
31.2902 + ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
31.2903 + var tagNameLower = ko.utils.tagNameLower(this.domElement),
31.2904 + elemContentsProperty = tagNameLower === "script" ? "text"
31.2905 + : tagNameLower === "textarea" ? "value"
31.2906 + : "innerHTML";
31.2907 +
31.2908 + if (arguments.length == 0) {
31.2909 + return this.domElement[elemContentsProperty];
31.2910 + } else {
31.2911 + var valueToWrite = arguments[0];
31.2912 + if (elemContentsProperty === "innerHTML")
31.2913 + ko.utils.setHtml(this.domElement, valueToWrite);
31.2914 + else
31.2915 + this.domElement[elemContentsProperty] = valueToWrite;
31.2916 + }
31.2917 + };
31.2918 +
31.2919 + ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
31.2920 + if (arguments.length === 1) {
31.2921 + return ko.utils.domData.get(this.domElement, "templateSourceData_" + key);
31.2922 + } else {
31.2923 + ko.utils.domData.set(this.domElement, "templateSourceData_" + key, arguments[1]);
31.2924 + }
31.2925 + };
31.2926 +
31.2927 + // ---- ko.templateSources.anonymousTemplate -----
31.2928 + // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
31.2929 + // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
31.2930 + // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
31.2931 +
31.2932 + var anonymousTemplatesDomDataKey = "__ko_anon_template__";
31.2933 + ko.templateSources.anonymousTemplate = function(element) {
31.2934 + this.domElement = element;
31.2935 + }
31.2936 + ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
31.2937 + ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
31.2938 + if (arguments.length == 0) {
31.2939 + var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
31.2940 + if (templateData.textData === undefined && templateData.containerData)
31.2941 + templateData.textData = templateData.containerData.innerHTML;
31.2942 + return templateData.textData;
31.2943 + } else {
31.2944 + var valueToWrite = arguments[0];
31.2945 + ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
31.2946 + }
31.2947 + };
31.2948 + ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
31.2949 + if (arguments.length == 0) {
31.2950 + var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
31.2951 + return templateData.containerData;
31.2952 + } else {
31.2953 + var valueToWrite = arguments[0];
31.2954 + ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
31.2955 + }
31.2956 + };
31.2957 +
31.2958 + ko.exportSymbol('templateSources', ko.templateSources);
31.2959 + ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
31.2960 + ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
31.2961 +})();
31.2962 +(function () {
31.2963 + var _templateEngine;
31.2964 + ko.setTemplateEngine = function (templateEngine) {
31.2965 + if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
31.2966 + throw new Error("templateEngine must inherit from ko.templateEngine");
31.2967 + _templateEngine = templateEngine;
31.2968 + }
31.2969 +
31.2970 + function invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, action) {
31.2971 + var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
31.2972 + while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
31.2973 + nextInQueue = ko.virtualElements.nextSibling(node);
31.2974 + if (node.nodeType === 1 || node.nodeType === 8)
31.2975 + action(node);
31.2976 + }
31.2977 + }
31.2978 +
31.2979 + function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
31.2980 + // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
31.2981 + // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
31.2982 + // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
31.2983 + // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
31.2984 + // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
31.2985 +
31.2986 + if (continuousNodeArray.length) {
31.2987 + var firstNode = continuousNodeArray[0], lastNode = continuousNodeArray[continuousNodeArray.length - 1];
31.2988 +
31.2989 + // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
31.2990 + // whereas a regular applyBindings won't introduce new memoized nodes
31.2991 + invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
31.2992 + ko.applyBindings(bindingContext, node);
31.2993 + });
31.2994 + invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
31.2995 + ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
31.2996 + });
31.2997 + }
31.2998 + }
31.2999 +
31.3000 + function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
31.3001 + return nodeOrNodeArray.nodeType ? nodeOrNodeArray
31.3002 + : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
31.3003 + : null;
31.3004 + }
31.3005 +
31.3006 + function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
31.3007 + options = options || {};
31.3008 + var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
31.3009 + var templateDocument = firstTargetNode && firstTargetNode.ownerDocument;
31.3010 + var templateEngineToUse = (options['templateEngine'] || _templateEngine);
31.3011 + ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
31.3012 + var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
31.3013 +
31.3014 + // Loosely check result is an array of DOM nodes
31.3015 + if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
31.3016 + throw new Error("Template engine must return an array of DOM nodes");
31.3017 +
31.3018 + var haveAddedNodesToParent = false;
31.3019 + switch (renderMode) {
31.3020 + case "replaceChildren":
31.3021 + ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
31.3022 + haveAddedNodesToParent = true;
31.3023 + break;
31.3024 + case "replaceNode":
31.3025 + ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
31.3026 + haveAddedNodesToParent = true;
31.3027 + break;
31.3028 + case "ignoreTargetNode": break;
31.3029 + default:
31.3030 + throw new Error("Unknown renderMode: " + renderMode);
31.3031 + }
31.3032 +
31.3033 + if (haveAddedNodesToParent) {
31.3034 + activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
31.3035 + if (options['afterRender'])
31.3036 + ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
31.3037 + }
31.3038 +
31.3039 + return renderedNodesArray;
31.3040 + }
31.3041 +
31.3042 + ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
31.3043 + options = options || {};
31.3044 + if ((options['templateEngine'] || _templateEngine) == undefined)
31.3045 + throw new Error("Set a template engine before calling renderTemplate");
31.3046 + renderMode = renderMode || "replaceChildren";
31.3047 +
31.3048 + if (targetNodeOrNodeArray) {
31.3049 + var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
31.3050 +
31.3051 + var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
31.3052 + var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
31.3053 +
31.3054 + return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
31.3055 + function () {
31.3056 + // Ensure we've got a proper binding context to work with
31.3057 + var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
31.3058 + ? dataOrBindingContext
31.3059 + : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
31.3060 +
31.3061 + // Support selecting template as a function of the data being rendered
31.3062 + var templateName = typeof(template) == 'function' ? template(bindingContext['$data'], bindingContext) : template;
31.3063 +
31.3064 + var renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
31.3065 + if (renderMode == "replaceNode") {
31.3066 + targetNodeOrNodeArray = renderedNodesArray;
31.3067 + firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
31.3068 + }
31.3069 + },
31.3070 + null,
31.3071 + { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
31.3072 + );
31.3073 + } else {
31.3074 + // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
31.3075 + return ko.memoization.memoize(function (domNode) {
31.3076 + ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
31.3077 + });
31.3078 + }
31.3079 + };
31.3080 +
31.3081 + ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
31.3082 + // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
31.3083 + // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
31.3084 + var arrayItemContext;
31.3085 +
31.3086 + // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
31.3087 + var executeTemplateForArrayItem = function (arrayValue, index) {
31.3088 + // Support selecting template as a function of the data being rendered
31.3089 + arrayItemContext = parentBindingContext['createChildContext'](ko.utils.unwrapObservable(arrayValue), options['as']);
31.3090 + arrayItemContext['$index'] = index;
31.3091 + var templateName = typeof(template) == 'function' ? template(arrayValue, arrayItemContext) : template;
31.3092 + return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
31.3093 + }
31.3094 +
31.3095 + // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
31.3096 + var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
31.3097 + activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
31.3098 + if (options['afterRender'])
31.3099 + options['afterRender'](addedNodesArray, arrayValue);
31.3100 + };
31.3101 +
31.3102 + return ko.dependentObservable(function () {
31.3103 + var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
31.3104 + if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
31.3105 + unwrappedArray = [unwrappedArray];
31.3106 +
31.3107 + // Filter out any entries marked as destroyed
31.3108 + var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
31.3109 + return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
31.3110 + });
31.3111 +
31.3112 + // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
31.3113 + // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
31.3114 + ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
31.3115 +
31.3116 + }, null, { disposeWhenNodeIsRemoved: targetNode });
31.3117 + };
31.3118 +
31.3119 + var templateComputedDomDataKey = '__ko__templateComputedDomDataKey__';
31.3120 + function disposeOldComputedAndStoreNewOne(element, newComputed) {
31.3121 + var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
31.3122 + if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
31.3123 + oldComputed.dispose();
31.3124 + ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
31.3125 + }
31.3126 +
31.3127 + ko.bindingHandlers['template'] = {
31.3128 + 'init': function(element, valueAccessor) {
31.3129 + // Support anonymous templates
31.3130 + var bindingValue = ko.utils.unwrapObservable(valueAccessor());
31.3131 + if ((typeof bindingValue != "string") && (!bindingValue['name']) && (element.nodeType == 1 || element.nodeType == 8)) {
31.3132 + // It's an anonymous template - store the element contents, then clear the element
31.3133 + var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element),
31.3134 + container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
31.3135 + new ko.templateSources.anonymousTemplate(element)['nodes'](container);
31.3136 + }
31.3137 + return { 'controlsDescendantBindings': true };
31.3138 + },
31.3139 + 'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
31.3140 + var templateName = ko.utils.unwrapObservable(valueAccessor()),
31.3141 + options = {},
31.3142 + shouldDisplay = true,
31.3143 + dataValue,
31.3144 + templateComputed = null;
31.3145 +
31.3146 + if (typeof templateName != "string") {
31.3147 + options = templateName;
31.3148 + templateName = options['name'];
31.3149 +
31.3150 + // Support "if"/"ifnot" conditions
31.3151 + if ('if' in options)
31.3152 + shouldDisplay = ko.utils.unwrapObservable(options['if']);
31.3153 + if (shouldDisplay && 'ifnot' in options)
31.3154 + shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
31.3155 +
31.3156 + dataValue = ko.utils.unwrapObservable(options['data']);
31.3157 + }
31.3158 +
31.3159 + if ('foreach' in options) {
31.3160 + // Render once for each data point (treating data set as empty if shouldDisplay==false)
31.3161 + var dataArray = (shouldDisplay && options['foreach']) || [];
31.3162 + templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
31.3163 + } else if (!shouldDisplay) {
31.3164 + ko.virtualElements.emptyNode(element);
31.3165 + } else {
31.3166 + // Render once for this single data point (or use the viewModel if no data was provided)
31.3167 + var innerBindingContext = ('data' in options) ?
31.3168 + bindingContext['createChildContext'](dataValue, options['as']) : // Given an explitit 'data' value, we create a child binding context for it
31.3169 + bindingContext; // Given no explicit 'data' value, we retain the same binding context
31.3170 + templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
31.3171 + }
31.3172 +
31.3173 + // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
31.3174 + disposeOldComputedAndStoreNewOne(element, templateComputed);
31.3175 + }
31.3176 + };
31.3177 +
31.3178 + // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
31.3179 + ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
31.3180 + var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
31.3181 +
31.3182 + if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
31.3183 + return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
31.3184 +
31.3185 + if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
31.3186 + return null; // Named templates can be rewritten, so return "no error"
31.3187 + return "This template engine does not support anonymous templates nested within its templates";
31.3188 + };
31.3189 +
31.3190 + ko.virtualElements.allowedBindings['template'] = true;
31.3191 +})();
31.3192 +
31.3193 +ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
31.3194 +ko.exportSymbol('renderTemplate', ko.renderTemplate);
31.3195 +
31.3196 +ko.utils.compareArrays = (function () {
31.3197 + var statusNotInOld = 'added', statusNotInNew = 'deleted';
31.3198 +
31.3199 + // Simple calculation based on Levenshtein distance.
31.3200 + function compareArrays(oldArray, newArray, dontLimitMoves) {
31.3201 + oldArray = oldArray || [];
31.3202 + newArray = newArray || [];
31.3203 +
31.3204 + if (oldArray.length <= newArray.length)
31.3205 + return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, dontLimitMoves);
31.3206 + else
31.3207 + return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, dontLimitMoves);
31.3208 + }
31.3209 +
31.3210 + function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, dontLimitMoves) {
31.3211 + var myMin = Math.min,
31.3212 + myMax = Math.max,
31.3213 + editDistanceMatrix = [],
31.3214 + smlIndex, smlIndexMax = smlArray.length,
31.3215 + bigIndex, bigIndexMax = bigArray.length,
31.3216 + compareRange = (bigIndexMax - smlIndexMax) || 1,
31.3217 + maxDistance = smlIndexMax + bigIndexMax + 1,
31.3218 + thisRow, lastRow,
31.3219 + bigIndexMaxForRow, bigIndexMinForRow;
31.3220 +
31.3221 + for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
31.3222 + lastRow = thisRow;
31.3223 + editDistanceMatrix.push(thisRow = []);
31.3224 + bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
31.3225 + bigIndexMinForRow = myMax(0, smlIndex - 1);
31.3226 + for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
31.3227 + if (!bigIndex)
31.3228 + thisRow[bigIndex] = smlIndex + 1;
31.3229 + else if (!smlIndex) // Top row - transform empty array into new array via additions
31.3230 + thisRow[bigIndex] = bigIndex + 1;
31.3231 + else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
31.3232 + thisRow[bigIndex] = lastRow[bigIndex - 1]; // copy value (no edit)
31.3233 + else {
31.3234 + var northDistance = lastRow[bigIndex] || maxDistance; // not in big (deletion)
31.3235 + var westDistance = thisRow[bigIndex - 1] || maxDistance; // not in small (addition)
31.3236 + thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
31.3237 + }
31.3238 + }
31.3239 + }
31.3240 +
31.3241 + var editScript = [], meMinusOne, notInSml = [], notInBig = [];
31.3242 + for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
31.3243 + meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
31.3244 + if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
31.3245 + notInSml.push(editScript[editScript.length] = { // added
31.3246 + 'status': statusNotInSml,
31.3247 + 'value': bigArray[--bigIndex],
31.3248 + 'index': bigIndex });
31.3249 + } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
31.3250 + notInBig.push(editScript[editScript.length] = { // deleted
31.3251 + 'status': statusNotInBig,
31.3252 + 'value': smlArray[--smlIndex],
31.3253 + 'index': smlIndex });
31.3254 + } else {
31.3255 + editScript.push({
31.3256 + 'status': "retained",
31.3257 + 'value': bigArray[--bigIndex] });
31.3258 + --smlIndex;
31.3259 + }
31.3260 + }
31.3261 +
31.3262 + if (notInSml.length && notInBig.length) {
31.3263 + // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
31.3264 + // smlIndexMax keeps the time complexity of this algorithm linear.
31.3265 + var limitFailedCompares = smlIndexMax * 10, failedCompares,
31.3266 + a, d, notInSmlItem, notInBigItem;
31.3267 + // Go through the items that have been added and deleted and try to find matches between them.
31.3268 + for (failedCompares = a = 0; (dontLimitMoves || failedCompares < limitFailedCompares) && (notInSmlItem = notInSml[a]); a++) {
31.3269 + for (d = 0; notInBigItem = notInBig[d]; d++) {
31.3270 + if (notInSmlItem['value'] === notInBigItem['value']) {
31.3271 + notInSmlItem['moved'] = notInBigItem['index'];
31.3272 + notInBigItem['moved'] = notInSmlItem['index'];
31.3273 + notInBig.splice(d,1); // This item is marked as moved; so remove it from notInBig list
31.3274 + failedCompares = d = 0; // Reset failed compares count because we're checking for consecutive failures
31.3275 + break;
31.3276 + }
31.3277 + }
31.3278 + failedCompares += d;
31.3279 + }
31.3280 + }
31.3281 + return editScript.reverse();
31.3282 + }
31.3283 +
31.3284 + return compareArrays;
31.3285 +})();
31.3286 +
31.3287 +ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
31.3288 +
31.3289 +(function () {
31.3290 + // Objective:
31.3291 + // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
31.3292 + // map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
31.3293 + // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
31.3294 + // so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
31.3295 + // previously mapped - retain those nodes, and just insert/delete other ones
31.3296 +
31.3297 + // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
31.3298 + // You can use this, for example, to activate bindings on those nodes.
31.3299 +
31.3300 + function fixUpNodesToBeMovedOrRemoved(contiguousNodeArray) {
31.3301 + // Before moving, deleting, or replacing a set of nodes that were previously outputted by the "map" function, we have to reconcile
31.3302 + // them against what is in the DOM right now. It may be that some of the nodes have already been removed from the document,
31.3303 + // or that new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
31.3304 + // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
31.3305 + // So, this function translates the old "map" output array into its best guess of what set of current DOM nodes should be removed.
31.3306 + //
31.3307 + // Rules:
31.3308 + // [A] Any leading nodes that aren't in the document any more should be ignored
31.3309 + // These most likely correspond to memoization nodes that were already removed during binding
31.3310 + // See https://github.com/SteveSanderson/knockout/pull/440
31.3311 + // [B] We want to output a contiguous series of nodes that are still in the document. So, ignore any nodes that
31.3312 + // have already been removed, and include any nodes that have been inserted among the previous collection
31.3313 +
31.3314 + // Rule [A]
31.3315 + while (contiguousNodeArray.length && !ko.utils.domNodeIsAttachedToDocument(contiguousNodeArray[0]))
31.3316 + contiguousNodeArray.splice(0, 1);
31.3317 +
31.3318 + // Rule [B]
31.3319 + if (contiguousNodeArray.length > 1) {
31.3320 + // Build up the actual new contiguous node set
31.3321 + var current = contiguousNodeArray[0], last = contiguousNodeArray[contiguousNodeArray.length - 1], newContiguousSet = [current];
31.3322 + while (current !== last) {
31.3323 + current = current.nextSibling;
31.3324 + if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
31.3325 + return;
31.3326 + newContiguousSet.push(current);
31.3327 + }
31.3328 +
31.3329 + // ... then mutate the input array to match this.
31.3330 + // (The following line replaces the contents of contiguousNodeArray with newContiguousSet)
31.3331 + Array.prototype.splice.apply(contiguousNodeArray, [0, contiguousNodeArray.length].concat(newContiguousSet));
31.3332 + }
31.3333 + return contiguousNodeArray;
31.3334 + }
31.3335 +
31.3336 + function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
31.3337 + // Map this array value inside a dependentObservable so we re-map when any dependency changes
31.3338 + var mappedNodes = [];
31.3339 + var dependentObservable = ko.dependentObservable(function() {
31.3340 + var newMappedNodes = mapping(valueToMap, index) || [];
31.3341 +
31.3342 + // On subsequent evaluations, just replace the previously-inserted DOM nodes
31.3343 + if (mappedNodes.length > 0) {
31.3344 + ko.utils.replaceDomNodes(fixUpNodesToBeMovedOrRemoved(mappedNodes), newMappedNodes);
31.3345 + if (callbackAfterAddingNodes)
31.3346 + ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
31.3347 + }
31.3348 +
31.3349 + // Replace the contents of the mappedNodes array, thereby updating the record
31.3350 + // of which nodes would be deleted if valueToMap was itself later removed
31.3351 + mappedNodes.splice(0, mappedNodes.length);
31.3352 + ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
31.3353 + }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
31.3354 + return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
31.3355 + }
31.3356 +
31.3357 + var lastMappingResultDomDataKey = "setDomNodeChildrenFromArrayMapping_lastMappingResult";
31.3358 +
31.3359 + ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
31.3360 + // Compare the provided array against the previous one
31.3361 + array = array || [];
31.3362 + options = options || {};
31.3363 + var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
31.3364 + var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
31.3365 + var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
31.3366 + var editScript = ko.utils.compareArrays(lastArray, array);
31.3367 +
31.3368 + // Build the new mapping result
31.3369 + var newMappingResult = [];
31.3370 + var lastMappingResultIndex = 0;
31.3371 + var newMappingResultIndex = 0;
31.3372 +
31.3373 + var nodesToDelete = [];
31.3374 + var itemsToProcess = [];
31.3375 + var itemsForBeforeRemoveCallbacks = [];
31.3376 + var itemsForMoveCallbacks = [];
31.3377 + var itemsForAfterAddCallbacks = [];
31.3378 + var mapData;
31.3379 +
31.3380 + function itemMovedOrRetained(editScriptIndex, oldPosition) {
31.3381 + mapData = lastMappingResult[oldPosition];
31.3382 + if (newMappingResultIndex !== oldPosition)
31.3383 + itemsForMoveCallbacks[editScriptIndex] = mapData;
31.3384 + // Since updating the index might change the nodes, do so before calling fixUpNodesToBeMovedOrRemoved
31.3385 + mapData.indexObservable(newMappingResultIndex++);
31.3386 + fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes);
31.3387 + newMappingResult.push(mapData);
31.3388 + itemsToProcess.push(mapData);
31.3389 + }
31.3390 +
31.3391 + function callCallback(callback, items) {
31.3392 + if (callback) {
31.3393 + for (var i = 0, n = items.length; i < n; i++) {
31.3394 + if (items[i]) {
31.3395 + ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
31.3396 + callback(node, i, items[i].arrayEntry);
31.3397 + });
31.3398 + }
31.3399 + }
31.3400 + }
31.3401 + }
31.3402 +
31.3403 + for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
31.3404 + movedIndex = editScriptItem['moved'];
31.3405 + switch (editScriptItem['status']) {
31.3406 + case "deleted":
31.3407 + if (movedIndex === undefined) {
31.3408 + mapData = lastMappingResult[lastMappingResultIndex];
31.3409 +
31.3410 + // Stop tracking changes to the mapping for these nodes
31.3411 + if (mapData.dependentObservable)
31.3412 + mapData.dependentObservable.dispose();
31.3413 +
31.3414 + // Queue these nodes for later removal
31.3415 + nodesToDelete.push.apply(nodesToDelete, fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes));
31.3416 + if (options['beforeRemove']) {
31.3417 + itemsForBeforeRemoveCallbacks[i] = mapData;
31.3418 + itemsToProcess.push(mapData);
31.3419 + }
31.3420 + }
31.3421 + lastMappingResultIndex++;
31.3422 + break;
31.3423 +
31.3424 + case "retained":
31.3425 + itemMovedOrRetained(i, lastMappingResultIndex++);
31.3426 + break;
31.3427 +
31.3428 + case "added":
31.3429 + if (movedIndex !== undefined) {
31.3430 + itemMovedOrRetained(i, movedIndex);
31.3431 + } else {
31.3432 + mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
31.3433 + newMappingResult.push(mapData);
31.3434 + itemsToProcess.push(mapData);
31.3435 + if (!isFirstExecution)
31.3436 + itemsForAfterAddCallbacks[i] = mapData;
31.3437 + }
31.3438 + break;
31.3439 + }
31.3440 + }
31.3441 +
31.3442 + // Call beforeMove first before any changes have been made to the DOM
31.3443 + callCallback(options['beforeMove'], itemsForMoveCallbacks);
31.3444 +
31.3445 + // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
31.3446 + ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
31.3447 +
31.3448 + // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
31.3449 + for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
31.3450 + // Get nodes for newly added items
31.3451 + if (!mapData.mappedNodes)
31.3452 + ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
31.3453 +
31.3454 + // Put nodes in the right place if they aren't there already
31.3455 + for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
31.3456 + if (node !== nextNode)
31.3457 + ko.virtualElements.insertAfter(domNode, node, lastNode);
31.3458 + }
31.3459 +
31.3460 + // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
31.3461 + if (!mapData.initialized && callbackAfterAddingNodes) {
31.3462 + callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
31.3463 + mapData.initialized = true;
31.3464 + }
31.3465 + }
31.3466 +
31.3467 + // If there's a beforeRemove callback, call it after reordering.
31.3468 + // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
31.3469 + // some sort of animation, which is why we first reorder the nodes that will be removed. If the
31.3470 + // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
31.3471 + // Perhaps we'll make that change in the future if this scenario becomes more common.
31.3472 + callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
31.3473 +
31.3474 + // Finally call afterMove and afterAdd callbacks
31.3475 + callCallback(options['afterMove'], itemsForMoveCallbacks);
31.3476 + callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
31.3477 +
31.3478 + // Store a copy of the array items we just considered so we can difference it next time
31.3479 + ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
31.3480 + }
31.3481 +})();
31.3482 +
31.3483 +ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
31.3484 +ko.nativeTemplateEngine = function () {
31.3485 + this['allowTemplateRewriting'] = false;
31.3486 +}
31.3487 +
31.3488 +ko.nativeTemplateEngine.prototype = new ko.templateEngine();
31.3489 +ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
31.3490 + var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
31.3491 + templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
31.3492 + templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
31.3493 +
31.3494 + if (templateNodes) {
31.3495 + return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
31.3496 + } else {
31.3497 + var templateText = templateSource['text']();
31.3498 + return ko.utils.parseHtmlFragment(templateText);
31.3499 + }
31.3500 +};
31.3501 +
31.3502 +ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
31.3503 +ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
31.3504 +
31.3505 +ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
31.3506 +(function() {
31.3507 + ko.jqueryTmplTemplateEngine = function () {
31.3508 + // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
31.3509 + // doesn't expose a version number, so we have to infer it.
31.3510 + // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
31.3511 + // which KO internally refers to as version "2", so older versions are no longer detected.
31.3512 + var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
31.3513 + if ((typeof(jQuery) == "undefined") || !(jQuery['tmpl']))
31.3514 + return 0;
31.3515 + // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
31.3516 + try {
31.3517 + if (jQuery['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
31.3518 + // Since 1.0.0pre, custom tags should append markup to an array called "__"
31.3519 + return 2; // Final version of jquery.tmpl
31.3520 + }
31.3521 + } catch(ex) { /* Apparently not the version we were looking for */ }
31.3522 +
31.3523 + return 1; // Any older version that we don't support
31.3524 + })();
31.3525 +
31.3526 + function ensureHasReferencedJQueryTemplates() {
31.3527 + if (jQueryTmplVersion < 2)
31.3528 + throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
31.3529 + }
31.3530 +
31.3531 + function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
31.3532 + return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
31.3533 + }
31.3534 +
31.3535 + this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
31.3536 + options = options || {};
31.3537 + ensureHasReferencedJQueryTemplates();
31.3538 +
31.3539 + // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
31.3540 + var precompiled = templateSource['data']('precompiled');
31.3541 + if (!precompiled) {
31.3542 + var templateText = templateSource['text']() || "";
31.3543 + // Wrap in "with($whatever.koBindingContext) { ... }"
31.3544 + templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
31.3545 +
31.3546 + precompiled = jQuery['template'](null, templateText);
31.3547 + templateSource['data']('precompiled', precompiled);
31.3548 + }
31.3549 +
31.3550 + var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
31.3551 + var jQueryTemplateOptions = jQuery['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
31.3552 +
31.3553 + var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
31.3554 + resultNodes['appendTo'](document.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
31.3555 +
31.3556 + jQuery['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
31.3557 + return resultNodes;
31.3558 + };
31.3559 +
31.3560 + this['createJavaScriptEvaluatorBlock'] = function(script) {
31.3561 + return "{{ko_code ((function() { return " + script + " })()) }}";
31.3562 + };
31.3563 +
31.3564 + this['addTemplate'] = function(templateName, templateMarkup) {
31.3565 + document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "</script>");
31.3566 + };
31.3567 +
31.3568 + if (jQueryTmplVersion > 0) {
31.3569 + jQuery['tmpl']['tag']['ko_code'] = {
31.3570 + open: "__.push($1 || '');"
31.3571 + };
31.3572 + jQuery['tmpl']['tag']['ko_with'] = {
31.3573 + open: "with($1) {",
31.3574 + close: "} "
31.3575 + };
31.3576 + }
31.3577 + };
31.3578 +
31.3579 + ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
31.3580 +
31.3581 + // Use this one by default *only if jquery.tmpl is referenced*
31.3582 + var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
31.3583 + if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
31.3584 + ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
31.3585 +
31.3586 + ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
31.3587 +})();
31.3588 +});
31.3589 +})(window,document,navigator,window["jQuery"]);
31.3590 +})();
31.3591 \ No newline at end of file
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/KnockoutTest.java Wed Jan 23 12:53:23 2013 +0100
32.3 @@ -0,0 +1,62 @@
32.4 +/**
32.5 + * Back 2 Browser Bytecode Translator
32.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
32.7 + *
32.8 + * This program is free software: you can redistribute it and/or modify
32.9 + * it under the terms of the GNU General Public License as published by
32.10 + * the Free Software Foundation, version 2 of the License.
32.11 + *
32.12 + * This program is distributed in the hope that it will be useful,
32.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
32.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32.15 + * GNU General Public License for more details.
32.16 + *
32.17 + * You should have received a copy of the GNU General Public License
32.18 + * along with this program. Look for COPYING file in the top folder.
32.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
32.20 + */
32.21 +package org.apidesign.bck2brwsr.htmlpage;
32.22 +
32.23 +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
32.24 +import org.apidesign.bck2brwsr.htmlpage.api.OnEvent;
32.25 +import org.apidesign.bck2brwsr.htmlpage.api.Page;
32.26 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
32.27 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
32.28 +import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
32.29 +import org.apidesign.bck2brwsr.vmtest.VMTest;
32.30 +import org.testng.annotations.Factory;
32.31 +
32.32 +/**
32.33 + *
32.34 + * @author Jaroslav Tulach <jtulach@netbeans.org>
32.35 + */
32.36 +@Page(xhtml="Knockout.xhtml", className="KnockoutModel", properties={
32.37 + @Property(name="name", type=String.class)
32.38 +})
32.39 +public class KnockoutTest {
32.40 +
32.41 + @HtmlFragment(
32.42 + "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
32.43 + "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
32.44 + "<button id=\"hello\">Say Hello!</button>\n"
32.45 + )
32.46 + @BrwsrTest public void modifyValueAssertChangeInModel() {
32.47 + KnockoutModel m = new KnockoutModel();
32.48 + m.setName("Kukuc");
32.49 + m.applyBindings();
32.50 + assert "Kukuc".equals(m.INPUT.getValue()) : "Value is really kukuc: " + m.INPUT.getValue();
32.51 + m.INPUT.setValue("Jardo");
32.52 + m.triggerEvent(m.INPUT, OnEvent.CHANGE);
32.53 + assert "Jardo".equals(m.getName()) : "Name property updated: " + m.getName();
32.54 + }
32.55 +
32.56 + @ComputedProperty
32.57 + static String helloMessage(String name) {
32.58 + return "Hello " + name + "!";
32.59 + }
32.60 +
32.61 + @Factory
32.62 + public static Object[] create() {
32.63 + return VMTest.create(KnockoutTest.class);
32.64 + }
32.65 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Wed Jan 23 12:53:23 2013 +0100
33.3 @@ -0,0 +1,119 @@
33.4 +/**
33.5 + * Back 2 Browser Bytecode Translator
33.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
33.7 + *
33.8 + * This program is free software: you can redistribute it and/or modify
33.9 + * it under the terms of the GNU General Public License as published by
33.10 + * the Free Software Foundation, version 2 of the License.
33.11 + *
33.12 + * This program is distributed in the hope that it will be useful,
33.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
33.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33.15 + * GNU General Public License for more details.
33.16 + *
33.17 + * You should have received a copy of the GNU General Public License
33.18 + * along with this program. Look for COPYING file in the top folder.
33.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
33.20 + */
33.21 +package org.apidesign.bck2brwsr.htmlpage;
33.22 +
33.23 +import java.util.ArrayList;
33.24 +import java.util.List;
33.25 +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
33.26 +import org.apidesign.bck2brwsr.htmlpage.api.Page;
33.27 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
33.28 +import static org.testng.Assert.*;
33.29 +import org.testng.annotations.BeforeMethod;
33.30 +import org.testng.annotations.Test;
33.31 +
33.32 +/**
33.33 + *
33.34 + * @author Jaroslav Tulach <jtulach@netbeans.org>
33.35 + */
33.36 +@Page(xhtml = "Empty.html", className = "Model", properties = {
33.37 + @Property(name = "value", type = int.class),
33.38 + @Property(name = "unrelated", type = long.class)
33.39 +})
33.40 +public class ModelTest {
33.41 + private Model model;
33.42 + private static Model leakedModel;
33.43 +
33.44 + @BeforeMethod
33.45 + public void createModel() {
33.46 + model = new Model();
33.47 + }
33.48 +
33.49 + @Test public void classGeneratedWithSetterGetter() {
33.50 + model.setValue(10);
33.51 + assertEquals(10, model.getValue(), "Value changed");
33.52 + }
33.53 +
33.54 + @Test public void computedMethod() {
33.55 + model.setValue(4);
33.56 + assertEquals(16, model.getPowerValue());
33.57 + }
33.58 +
33.59 + @Test public void derivedPropertiesAreNotified() {
33.60 + MockKnockout my = new MockKnockout();
33.61 + MockKnockout.next = my;
33.62 +
33.63 + model.applyBindings();
33.64 +
33.65 + model.setValue(33);
33.66 +
33.67 + assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated);
33.68 + assertTrue(my.mutated.contains("powerValue"), "Power value is in there: " + my.mutated);
33.69 + assertTrue(my.mutated.contains("value"), "Simple value is in there: " + my.mutated);
33.70 +
33.71 + my.mutated.clear();
33.72 +
33.73 + model.setUnrelated(44);
33.74 + assertEquals(my.mutated.size(), 1, "One property changed");
33.75 + assertTrue(my.mutated.contains("unrelated"), "Its name is unrelated");
33.76 + }
33.77 +
33.78 + @Test public void computedPropertyCannotWriteToModel() {
33.79 + leakedModel = model;
33.80 + try {
33.81 + String res = model.getNotAllowedWrite();
33.82 + fail("We should not be allowed to write to the model: " + res);
33.83 + } catch (IllegalStateException ex) {
33.84 + // OK, we can't read
33.85 + }
33.86 + }
33.87 +
33.88 + @Test public void computedPropertyCannotReadToModel() {
33.89 + leakedModel = model;
33.90 + try {
33.91 + String res = model.getNotAllowedRead();
33.92 + fail("We should not be allowed to read from the model: " + res);
33.93 + } catch (IllegalStateException ex) {
33.94 + // OK, we can't read
33.95 + }
33.96 + }
33.97 +
33.98 + @ComputedProperty
33.99 + static int powerValue(int value) {
33.100 + return value * value;
33.101 + }
33.102 +
33.103 + @ComputedProperty
33.104 + static String notAllowedRead() {
33.105 + return "Not allowed callback: " + leakedModel.getUnrelated();
33.106 + }
33.107 +
33.108 + @ComputedProperty
33.109 + static String notAllowedWrite() {
33.110 + leakedModel.setUnrelated(11);
33.111 + return "Not allowed callback!";
33.112 + }
33.113 +
33.114 + static class MockKnockout extends Knockout {
33.115 + List<String> mutated = new ArrayList<String>();
33.116 +
33.117 + @Override
33.118 + public void valueHasMutated(String prop) {
33.119 + mutated.add(prop);
33.120 + }
33.121 + }
33.122 +}
34.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Tue Jan 22 19:48:10 2013 +0100
34.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/PageController.java Wed Jan 23 12:53:23 2013 +0100
34.3 @@ -43,9 +43,14 @@
34.4 */
34.5 @Page(xhtml="TestPage.html")
34.6 public class PageController {
34.7 + private static final TestPage PAGE = new TestPage();
34.8 +
34.9 @On(event = CLICK, id="pg.button")
34.10 - static void updateTitle() {
34.11 - TestPage.PG_TITLE.setText("You want this window to be named " + TestPage.PG_TEXT.getValue());
34.12 + static void updateTitle(TestPage ref) {
34.13 + if (PAGE != ref) {
34.14 + throw new IllegalStateException("Both references should be the same. " + ref + " != " + PAGE);
34.15 + }
34.16 + ref.PG_TITLE.setText("You want this window to be named " + ref.PG_TEXT.getValue());
34.17 }
34.18
34.19 @On(event = CLICK, id={ "pg.title", "pg.text" })
34.20 @@ -53,6 +58,6 @@
34.21 if (!id.equals("pg.title")) {
34.22 throw new IllegalStateException();
34.23 }
34.24 - TestPage.PG_TITLE.setText(id);
34.25 + PAGE.PG_TITLE.setText(id);
34.26 }
34.27 }
35.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Tue Jan 22 19:48:10 2013 +0100
35.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Wed Jan 23 12:53:23 2013 +0100
35.3 @@ -108,7 +108,9 @@
35.4 + "\n"
35.5 + "window.document = doc;\n"
35.6 );
35.7 - Invocable i = compileClass(sb, "org/apidesign/bck2brwsr/htmlpage/PageController");
35.8 + Invocable i = compileClass(sb,
35.9 + "org/apidesign/bck2brwsr/htmlpage/PageController"
35.10 + );
35.11
35.12 Object ret = null;
35.13 try {
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/Empty.html Wed Jan 23 12:53:23 2013 +0100
36.3 @@ -0,0 +1,29 @@
36.4 +<?xml version="1.0" encoding="UTF-8"?>
36.5 +<!--
36.6 +
36.7 + Back 2 Browser Bytecode Translator
36.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
36.9 +
36.10 + This program is free software: you can redistribute it and/or modify
36.11 + it under the terms of the GNU General Public License as published by
36.12 + the Free Software Foundation, version 2 of the License.
36.13 +
36.14 + This program is distributed in the hope that it will be useful,
36.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
36.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36.17 + GNU General Public License for more details.
36.18 +
36.19 + You should have received a copy of the GNU General Public License
36.20 + along with this program. Look for COPYING file in the top folder.
36.21 + If not, see http://opensource.org/licenses/GPL-2.0.
36.22 +
36.23 +-->
36.24 +<!DOCTYPE html>
36.25 +<html xmlns="http://www.w3.org/1999/xhtml">
36.26 + <head>
36.27 + <title>Empty</title>
36.28 + </head>
36.29 + <body>
36.30 + Empty page
36.31 + </body>
36.32 +</html>
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/javaquery/api/src/test/resources/org/apidesign/bck2brwsr/htmlpage/Knockout.xhtml Wed Jan 23 12:53:23 2013 +0100
37.3 @@ -0,0 +1,25 @@
37.4 +<?xml version="1.0" encoding="UTF-8"?>
37.5 +<!--
37.6 +
37.7 + Back 2 Browser Bytecode Translator
37.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
37.9 +
37.10 + This program is free software: you can redistribute it and/or modify
37.11 + it under the terms of the GNU General Public License as published by
37.12 + the Free Software Foundation, version 2 of the License.
37.13 +
37.14 + This program is distributed in the hope that it will be useful,
37.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
37.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37.17 + GNU General Public License for more details.
37.18 +
37.19 + You should have received a copy of the GNU General Public License
37.20 + along with this program. Look for COPYING file in the top folder.
37.21 + If not, see http://opensource.org/licenses/GPL-2.0.
37.22 +
37.23 +-->
37.24 +<p>
37.25 + <h1 data-bind="text: helloMessage">Loading Bck2Brwsr's Hello World...</h1>
37.26 + Your name: <input id="input" data-bind="value: name, valueUpdate: 'afterkeydown'"></input>
37.27 + <button id="hello">Say Hello!</button>
37.28 +</p>
38.1 --- a/javaquery/demo-calculator-dynamic/pom.xml Tue Jan 22 19:48:10 2013 +0100
38.2 +++ b/javaquery/demo-calculator-dynamic/pom.xml Wed Jan 23 12:53:23 2013 +0100
38.3 @@ -28,7 +28,7 @@
38.4 </execution>
38.5 </executions>
38.6 <configuration>
38.7 - <startpage>org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml</startpage>
38.8 + <startpage>org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml</startpage>
38.9 </configuration>
38.10 </plugin>
38.11 <plugin>
38.12 @@ -54,5 +54,11 @@
38.13 <artifactId>javaquery.api</artifactId>
38.14 <version>0.3-SNAPSHOT</version>
38.15 </dependency>
38.16 + <dependency>
38.17 + <groupId>org.testng</groupId>
38.18 + <artifactId>testng</artifactId>
38.19 + <version>6.5.2</version>
38.20 + <scope>test</scope>
38.21 + </dependency>
38.22 </dependencies>
38.23 </project>
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
39.2 +++ b/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java Wed Jan 23 12:53:23 2013 +0100
39.3 @@ -0,0 +1,112 @@
39.4 +/**
39.5 + * Back 2 Browser Bytecode Translator
39.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
39.7 + *
39.8 + * This program is free software: you can redistribute it and/or modify
39.9 + * it under the terms of the GNU General Public License as published by
39.10 + * the Free Software Foundation, version 2 of the License.
39.11 + *
39.12 + * This program is distributed in the hope that it will be useful,
39.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
39.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39.15 + * GNU General Public License for more details.
39.16 + *
39.17 + * You should have received a copy of the GNU General Public License
39.18 + * along with this program. Look for COPYING file in the top folder.
39.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
39.20 + */
39.21 +package org.apidesign.bck2brwsr.demo.calc;
39.22 +
39.23 +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
39.24 +import org.apidesign.bck2brwsr.htmlpage.api.On;
39.25 +import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;
39.26 +import org.apidesign.bck2brwsr.htmlpage.api.Page;
39.27 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
39.28 +
39.29 +/** HTML5 & Java demo showing the power of
39.30 + * <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation processors</a>
39.31 + * as well as other goodies.
39.32 + *
39.33 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
39.34 + */
39.35 +@Page(xhtml="Calculator.xhtml", properties = {
39.36 + @Property(name = "memory", type = double.class),
39.37 + @Property(name = "display", type = double.class),
39.38 + @Property(name = "operation", type = String.class),
39.39 + @Property(name = "hover", type = boolean.class)
39.40 +})
39.41 +public class Calc {
39.42 + static {
39.43 + new Calculator().applyBindings();
39.44 + }
39.45 +
39.46 + @On(event = CLICK, id="clear")
39.47 + static void clear(Calculator c) {
39.48 + c.setMemory(0);
39.49 + c.setOperation(null);
39.50 + c.setDisplay(0);
39.51 + }
39.52 +
39.53 + @On(event = CLICK, id= { "plus", "minus", "mul", "div" })
39.54 + static void applyOp(Calculator c, String op) {
39.55 + c.setMemory(c.getDisplay());
39.56 + c.setOperation(op);
39.57 + c.setDisplay(0);
39.58 + }
39.59 +
39.60 + @On(event = MOUSE_OVER, id= { "result" })
39.61 + static void attemptingIn(Calculator c, String op) {
39.62 + c.setHover(true);
39.63 + }
39.64 + @On(event = MOUSE_OUT, id= { "result" })
39.65 + static void attemptingOut(Calculator c, String op) {
39.66 + c.setHover(false);
39.67 + }
39.68 +
39.69 + @On(event = CLICK, id="result")
39.70 + static void computeTheValue(Calculator c) {
39.71 + c.setDisplay(compute(
39.72 + c.getOperation(),
39.73 + c.getMemory(),
39.74 + c.getDisplay()
39.75 + ));
39.76 + c.setMemory(0);
39.77 + }
39.78 +
39.79 + private static double compute(String op, double memory, double display) {
39.80 + switch (op) {
39.81 + case "plus": return memory + display;
39.82 + case "minus": return memory - display;
39.83 + case "mul": return memory * display;
39.84 + case "div": return memory / display;
39.85 + default: throw new IllegalStateException(op);
39.86 + }
39.87 + }
39.88 +
39.89 + @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"})
39.90 + static void addDigit(String digit, Calculator c) {
39.91 + digit = digit.substring(1);
39.92 +
39.93 + double v = c.getDisplay();
39.94 + if (v == 0.0) {
39.95 + c.setDisplay(Integer.parseInt(digit));
39.96 + } else {
39.97 + String txt = Double.toString(v);
39.98 + if (txt.endsWith(".0")) {
39.99 + txt = txt.substring(0, txt.length() - 2);
39.100 + }
39.101 + txt = txt + digit;
39.102 + c.setDisplay(Double.parseDouble(txt));
39.103 + }
39.104 + }
39.105 +
39.106 + @ComputedProperty
39.107 + public static String displayPreview(
39.108 + double display, boolean hover, double memory, String operation
39.109 + ) {
39.110 + if (!hover) {
39.111 + return "Type numbers and perform simple operations! Press '=' to get result.";
39.112 + }
39.113 + return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display);
39.114 + }
39.115 +}
40.1 --- a/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Tue Jan 22 19:48:10 2013 +0100
40.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
40.3 @@ -1,89 +0,0 @@
40.4 -/**
40.5 - * Back 2 Browser Bytecode Translator
40.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
40.7 - *
40.8 - * This program is free software: you can redistribute it and/or modify
40.9 - * it under the terms of the GNU General Public License as published by
40.10 - * the Free Software Foundation, version 2 of the License.
40.11 - *
40.12 - * This program is distributed in the hope that it will be useful,
40.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
40.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40.15 - * GNU General Public License for more details.
40.16 - *
40.17 - * You should have received a copy of the GNU General Public License
40.18 - * along with this program. Look for COPYING file in the top folder.
40.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
40.20 - */
40.21 -package org.apidesign.bck2brwsr.mavenhtml;
40.22 -
40.23 -import org.apidesign.bck2brwsr.htmlpage.api.On;
40.24 -import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;
40.25 -import org.apidesign.bck2brwsr.htmlpage.api.Page;
40.26 -
40.27 -/** HTML5 & Java demo showing the power of
40.28 - * <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation processors</a>
40.29 - * as well as other goodies.
40.30 - *
40.31 - * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
40.32 - */
40.33 -@Page(xhtml="Calculator.xhtml")
40.34 -public class App {
40.35 - private static double memory;
40.36 - private static String operation;
40.37 -
40.38 - @On(event = CLICK, id="clear")
40.39 - static void clear() {
40.40 - memory = 0;
40.41 - operation = null;
40.42 - Calculator.DISPLAY.setValue("0");
40.43 - }
40.44 -
40.45 - @On(event = CLICK, id= { "plus", "minus", "mul", "div" })
40.46 - static void applyOp(String op) {
40.47 - memory = getValue();
40.48 - operation = op;
40.49 - Calculator.DISPLAY.setValue("0");
40.50 - }
40.51 -
40.52 - @On(event = CLICK, id="result")
40.53 - static void computeTheValue() {
40.54 - switch (operation) {
40.55 - case "plus": setValue(memory + getValue()); break;
40.56 - case "minus": setValue(memory - getValue()); break;
40.57 - case "mul": setValue(memory * getValue()); break;
40.58 - case "div": setValue(memory / getValue()); break;
40.59 - default: throw new IllegalStateException(operation);
40.60 - }
40.61 - }
40.62 -
40.63 - @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"})
40.64 - static void addDigit(String digit) {
40.65 - digit = digit.substring(1);
40.66 - String v = Calculator.DISPLAY.getValue();
40.67 - if (getValue() == 0.0) {
40.68 - Calculator.DISPLAY.setValue(digit);
40.69 - } else {
40.70 - Calculator.DISPLAY.setValue(v + digit);
40.71 - }
40.72 - }
40.73 -
40.74 - private static void setValue(double v) {
40.75 - StringBuilder sb = new StringBuilder();
40.76 - sb.append(v);
40.77 - if (sb.toString().endsWith(".0")) {
40.78 - final int l = sb.length();
40.79 - sb.delete(l - 2, l);
40.80 - }
40.81 - Calculator.DISPLAY.setValue(sb.toString());
40.82 - }
40.83 -
40.84 - private static double getValue() {
40.85 - try {
40.86 - return Double.parseDouble(Calculator.DISPLAY.getValue());
40.87 - } catch (NumberFormatException ex) {
40.88 - Calculator.DISPLAY.setValue("err");
40.89 - return 0.0;
40.90 - }
40.91 - }
40.92 -}
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
41.2 +++ b/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/demo/calc/Calculator.xhtml Wed Jan 23 12:53:23 2013 +0100
41.3 @@ -0,0 +1,159 @@
41.4 +<?xml version="1.0" encoding="UTF-8"?>
41.5 +<!--
41.6 +
41.7 + Back 2 Browser Bytecode Translator
41.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
41.9 +
41.10 + This program is free software: you can redistribute it and/or modify
41.11 + it under the terms of the GNU General Public License as published by
41.12 + the Free Software Foundation, version 2 of the License.
41.13 +
41.14 + This program is distributed in the hope that it will be useful,
41.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
41.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41.17 + GNU General Public License for more details.
41.18 +
41.19 + You should have received a copy of the GNU General Public License
41.20 + along with this program. Look for COPYING file in the top folder.
41.21 + If not, see http://opensource.org/licenses/GPL-2.0.
41.22 +
41.23 +-->
41.24 +<!DOCTYPE html>
41.25 +<html xmlns="http://www.w3.org/1999/xhtml">
41.26 + <head>
41.27 + <title>Simple Calculator in HTML5 and Java</title>
41.28 +
41.29 + <style type="text/css">
41.30 + body {color: #ffffff; background-color: #121e31; font-family: Monospaced}
41.31 + pre {color: #ffffff; background-color: #121e31; font-family: Monospaced}
41.32 + table {color: #ffffff; background-color: #121e31; font-family: Monospaced}
41.33 + .string {color: #e2ce00}
41.34 + a {color: #e2ce00}
41.35 + .ST1 {color: #0000cc; font-family: Monospaced; font-weight: bold}
41.36 + .ST0 {color: #0000ff}
41.37 + .comment {color: #428bdd}
41.38 + .keyword-directive {color: #f8bb00}
41.39 + .tag {color: #f8bb00}
41.40 + .ST0 {color: #628fb5; background-color: #1b3450}
41.41 + .sgml-comment {color: #808080}
41.42 + .value {color: #99006b}
41.43 + .argument {color: #007c00}
41.44 + .sgml-declaration {color: #bf9221}
41.45 + </style>
41.46 + </head>
41.47 + <body>
41.48 + <h1>Java and HTML5 - Together at Last!</h1>
41.49 + <table border="0" cellspacing="2">
41.50 + <tbody>
41.51 + <tr>
41.52 + <td colspan="4"><input data-bind="value: display" value="0"
41.53 + style="text-align: right"/>
41.54 + </td>
41.55 + </tr>
41.56 + <tr>
41.57 + <td><button id="n1">1</button></td>
41.58 + <td><button id="n2">2</button></td>
41.59 + <td><button id="n3">3</button></td>
41.60 + <td><button id="plus">+</button></td>
41.61 + </tr>
41.62 + <tr>
41.63 + <td><button id="n4">4</button></td>
41.64 + <td><button id="n5">5</button></td>
41.65 + <td><button id="n6">6</button></td>
41.66 + <td><button id="minus">-</button></td>
41.67 + </tr>
41.68 + <tr>
41.69 + <td><button id="n7">7</button></td>
41.70 + <td><button id="n8">8</button></td>
41.71 + <td><button id="n9">9</button></td>
41.72 + <td><button id="mul">*</button></td>
41.73 + </tr>
41.74 + <tr>
41.75 + <td><button id="clear">C</button></td>
41.76 + <td><button id="n0">0</button></td>
41.77 + <td><button id="result">=</button></td>
41.78 + <td><button id="div">/</button></td>
41.79 + </tr>
41.80 + </tbody>
41.81 + </table>
41.82 + <div data-bind="text: displayPreview"></div>
41.83 +
41.84 + <script src="/bck2brwsr.js"></script>
41.85 + <script src="/vm.js"></script>
41.86 + <script type="text/javascript">
41.87 + vm.loadClass('org.apidesign.bck2brwsr.demo.calc.Calc');
41.88 + </script>
41.89 +
41.90 + <hr/>
41.91 + <pre>
41.92 + <span class="keyword-directive">package</span> org.apidesign.bck2brwsr.mavenhtml;
41.93 +
41.94 + <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.OnClick;
41.95 + <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.Page;
41.96 +
41.97 + <span class="comment">/**</span> <span class="comment">HTML5</span><span class="comment"> & </span><span class="comment">Java</span> <span class="comment">demo</span> <span class="comment">showing</span> <span class="comment">the</span> <span class="comment">power</span> <span class="comment">of</span> <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation processors</a>
41.98 + <span class="comment"> * </span><span class="comment">as</span> <span class="comment">well</span> <span class="comment">as</span> <span class="comment">other</span> <span class="comment">goodies</span><span class="comment">, including type-safe association between</span>
41.99 + <span class="comment"> * </span><span class="comment">an XHTML page and Java.</span>
41.100 + <span class="comment"> * </span>
41.101 + <span class="comment"> * </span><span class="ST1">@author</span> <span class="comment">Jaroslav</span> <span class="comment">Tulach</span> <span class="ST0"><jaroslav.tulach@apidesign.org></span>
41.102 + <span class="comment">*/</span>
41.103 + @Page(xhtml=<span class="string">"</span><span class="string">Calculator.xhtml</span><span class="string">"</span>)
41.104 + <span class="keyword-directive">public</span> <span class="keyword-directive">class</span> App {
41.105 + <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> memory;
41.106 + <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> String operation;
41.107 +
41.108 + @OnClick(id=<span class="string">"</span><span class="string">clear</span><span class="string">"</span>)
41.109 + <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> clear() {
41.110 + memory = <span class="number">0</span>;
41.111 + operation = <span class="keyword-directive">null</span>;
41.112 + Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
41.113 + }
41.114 +
41.115 + @OnClick(id= { <span class="string">"</span><span class="string">plus</span><span class="string">"</span>, <span class="string">"</span><span class="string">minus</span><span class="string">"</span>, <span class="string">"</span><span class="string">mul</span><span class="string">"</span>, <span class="string">"</span><span class="string">div</span><span class="string">"</span> })
41.116 + <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> applyOp(String op) {
41.117 + memory = getValue();
41.118 + operation = op;
41.119 + Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
41.120 + }
41.121 +
41.122 + @OnClick(id=<span class="string">"</span><span class="string">result</span><span class="string">"</span>)
41.123 + <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> computeTheValue() {
41.124 + <span class="keyword-directive">switch</span> (operation) {
41.125 + <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">plus</span><span class="string">"</span>: setValue(memory + getValue()); <span class="keyword-directive">break</span>;
41.126 + <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">minus</span><span class="string">"</span>: setValue(memory - getValue()); <span class="keyword-directive">break</span>;
41.127 + <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">mul</span><span class="string">"</span>: setValue(memory * getValue()); <span class="keyword-directive">break</span>;
41.128 + <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">div</span><span class="string">"</span>: setValue(memory / getValue()); <span class="keyword-directive">break</span>;
41.129 + <span class="keyword-directive">default</span>: <span class="keyword-directive">throw</span> <span class="keyword-directive">new</span> IllegalStateException(operation);
41.130 + }
41.131 + }
41.132 +
41.133 + @OnClick(id={<span class="string">"</span><span class="string">n0</span><span class="string">"</span>, <span class="string">"</span><span class="string">n1</span><span class="string">"</span>, <span class="string">"</span><span class="string">n2</span><span class="string">"</span>, <span class="string">"</span><span class="string">n3</span><span class="string">"</span>, <span class="string">"</span><span class="string">n4</span><span class="string">"</span>, <span class="string">"</span><span class="string">n5</span><span class="string">"</span>, <span class="string">"</span><span class="string">n6</span><span class="string">"</span>, <span class="string">"</span><span class="string">n7</span><span class="string">"</span>, <span class="string">"</span><span class="string">n8</span><span class="string">"</span>, <span class="string">"</span><span class="string">n9</span><span class="string">"</span>})
41.134 + <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> addDigit(String digit) {
41.135 + digit = digit.substring(<span class="number">1</span>);
41.136 + String v = Calculator.DISPLAY.getValue();
41.137 + <span class="keyword-directive">if</span> (getValue() == <span class="number">0.0</span>) {
41.138 + Calculator.DISPLAY.setValue(digit);
41.139 + } <span class="keyword-directive">else</span> {
41.140 + Calculator.DISPLAY.setValue(v + digit);
41.141 + }
41.142 + }
41.143 +
41.144 + <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> setValue(<span class="keyword-directive">double</span> v) {
41.145 + StringBuilder sb = <span class="keyword-directive">new</span> StringBuilder();
41.146 + sb.append(v);
41.147 + Calculator.DISPLAY.setValue(sb.toString());
41.148 + }
41.149 +
41.150 + <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> getValue() {
41.151 + <span class="keyword-directive">try</span> {
41.152 + <span class="keyword-directive">return</span> Double.parseDouble(Calculator.DISPLAY.getValue());
41.153 + } <span class="keyword-directive">catch</span> (NumberFormatException ex) {
41.154 + Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">err</span><span class="string">"</span>);
41.155 + <span class="keyword-directive">return</span> <span class="number">0.0</span>;
41.156 + }
41.157 + }
41.158 + }
41.159 +
41.160 + </pre>
41.161 + </body>
41.162 +</html>
42.1 --- a/javaquery/demo-calculator-dynamic/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml Tue Jan 22 19:48:10 2013 +0100
42.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
42.3 @@ -1,158 +0,0 @@
42.4 -<?xml version="1.0" encoding="UTF-8"?>
42.5 -<!--
42.6 -
42.7 - Back 2 Browser Bytecode Translator
42.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
42.9 -
42.10 - This program is free software: you can redistribute it and/or modify
42.11 - it under the terms of the GNU General Public License as published by
42.12 - the Free Software Foundation, version 2 of the License.
42.13 -
42.14 - This program is distributed in the hope that it will be useful,
42.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
42.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42.17 - GNU General Public License for more details.
42.18 -
42.19 - You should have received a copy of the GNU General Public License
42.20 - along with this program. Look for COPYING file in the top folder.
42.21 - If not, see http://opensource.org/licenses/GPL-2.0.
42.22 -
42.23 --->
42.24 -<!DOCTYPE html>
42.25 -<html xmlns="http://www.w3.org/1999/xhtml">
42.26 - <head>
42.27 - <title>Simple Calculator in HTML5 and Java</title>
42.28 -
42.29 - <style type="text/css">
42.30 - body {color: #ffffff; background-color: #121e31; font-family: Monospaced}
42.31 - pre {color: #ffffff; background-color: #121e31; font-family: Monospaced}
42.32 - table {color: #ffffff; background-color: #121e31; font-family: Monospaced}
42.33 - .string {color: #e2ce00}
42.34 - a {color: #e2ce00}
42.35 - .ST1 {color: #0000cc; font-family: Monospaced; font-weight: bold}
42.36 - .ST0 {color: #0000ff}
42.37 - .comment {color: #428bdd}
42.38 - .keyword-directive {color: #f8bb00}
42.39 - .tag {color: #f8bb00}
42.40 - .ST0 {color: #628fb5; background-color: #1b3450}
42.41 - .sgml-comment {color: #808080}
42.42 - .value {color: #99006b}
42.43 - .argument {color: #007c00}
42.44 - .sgml-declaration {color: #bf9221}
42.45 - </style>
42.46 - </head>
42.47 - <body>
42.48 - <h1>Java and HTML5 - Together at Last!</h1>
42.49 - <table border="0" cellspacing="2">
42.50 - <tbody>
42.51 - <tr>
42.52 - <td colspan="4"><input id="display" value="0"
42.53 - style="text-align: right"/>
42.54 - </td>
42.55 - </tr>
42.56 - <tr>
42.57 - <td><button id="n1">1</button></td>
42.58 - <td><button id="n2">2</button></td>
42.59 - <td><button id="n3">3</button></td>
42.60 - <td><button id="plus">+</button></td>
42.61 - </tr>
42.62 - <tr>
42.63 - <td><button id="n4">4</button></td>
42.64 - <td><button id="n5">5</button></td>
42.65 - <td><button id="n6">6</button></td>
42.66 - <td><button id="minus">-</button></td>
42.67 - </tr>
42.68 - <tr>
42.69 - <td><button id="n7">7</button></td>
42.70 - <td><button id="n8">8</button></td>
42.71 - <td><button id="n9">9</button></td>
42.72 - <td><button id="mul">*</button></td>
42.73 - </tr>
42.74 - <tr>
42.75 - <td><button id="clear">C</button></td>
42.76 - <td><button id="n0">0</button></td>
42.77 - <td><button id="result">=</button></td>
42.78 - <td><button id="div">/</button></td>
42.79 - </tr>
42.80 - </tbody>
42.81 - </table>
42.82 -
42.83 - <script src="/bck2brwsr.js"></script>
42.84 - <script src="/vm.js"></script>
42.85 - <script type="text/javascript">
42.86 - vm.loadClass('org.apidesign.bck2brwsr.mavenhtml.Calculator');
42.87 - </script>
42.88 -
42.89 - <hr/>
42.90 - <pre>
42.91 - <span class="keyword-directive">package</span> org.apidesign.bck2brwsr.mavenhtml;
42.92 -
42.93 - <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.OnClick;
42.94 - <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.Page;
42.95 -
42.96 - <span class="comment">/**</span> <span class="comment">HTML5</span><span class="comment"> & </span><span class="comment">Java</span> <span class="comment">demo</span> <span class="comment">showing</span> <span class="comment">the</span> <span class="comment">power</span> <span class="comment">of</span> <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation processors</a>
42.97 - <span class="comment"> * </span><span class="comment">as</span> <span class="comment">well</span> <span class="comment">as</span> <span class="comment">other</span> <span class="comment">goodies</span><span class="comment">, including type-safe association between</span>
42.98 - <span class="comment"> * </span><span class="comment">an XHTML page and Java.</span>
42.99 - <span class="comment"> * </span>
42.100 - <span class="comment"> * </span><span class="ST1">@author</span> <span class="comment">Jaroslav</span> <span class="comment">Tulach</span> <span class="ST0"><jaroslav.tulach@apidesign.org></span>
42.101 - <span class="comment">*/</span>
42.102 - @Page(xhtml=<span class="string">"</span><span class="string">Calculator.xhtml</span><span class="string">"</span>)
42.103 - <span class="keyword-directive">public</span> <span class="keyword-directive">class</span> App {
42.104 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> memory;
42.105 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> String operation;
42.106 -
42.107 - @OnClick(id=<span class="string">"</span><span class="string">clear</span><span class="string">"</span>)
42.108 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> clear() {
42.109 - memory = <span class="number">0</span>;
42.110 - operation = <span class="keyword-directive">null</span>;
42.111 - Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
42.112 - }
42.113 -
42.114 - @OnClick(id= { <span class="string">"</span><span class="string">plus</span><span class="string">"</span>, <span class="string">"</span><span class="string">minus</span><span class="string">"</span>, <span class="string">"</span><span class="string">mul</span><span class="string">"</span>, <span class="string">"</span><span class="string">div</span><span class="string">"</span> })
42.115 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> applyOp(String op) {
42.116 - memory = getValue();
42.117 - operation = op;
42.118 - Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
42.119 - }
42.120 -
42.121 - @OnClick(id=<span class="string">"</span><span class="string">result</span><span class="string">"</span>)
42.122 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> computeTheValue() {
42.123 - <span class="keyword-directive">switch</span> (operation) {
42.124 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">plus</span><span class="string">"</span>: setValue(memory + getValue()); <span class="keyword-directive">break</span>;
42.125 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">minus</span><span class="string">"</span>: setValue(memory - getValue()); <span class="keyword-directive">break</span>;
42.126 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">mul</span><span class="string">"</span>: setValue(memory * getValue()); <span class="keyword-directive">break</span>;
42.127 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">div</span><span class="string">"</span>: setValue(memory / getValue()); <span class="keyword-directive">break</span>;
42.128 - <span class="keyword-directive">default</span>: <span class="keyword-directive">throw</span> <span class="keyword-directive">new</span> IllegalStateException(operation);
42.129 - }
42.130 - }
42.131 -
42.132 - @OnClick(id={<span class="string">"</span><span class="string">n0</span><span class="string">"</span>, <span class="string">"</span><span class="string">n1</span><span class="string">"</span>, <span class="string">"</span><span class="string">n2</span><span class="string">"</span>, <span class="string">"</span><span class="string">n3</span><span class="string">"</span>, <span class="string">"</span><span class="string">n4</span><span class="string">"</span>, <span class="string">"</span><span class="string">n5</span><span class="string">"</span>, <span class="string">"</span><span class="string">n6</span><span class="string">"</span>, <span class="string">"</span><span class="string">n7</span><span class="string">"</span>, <span class="string">"</span><span class="string">n8</span><span class="string">"</span>, <span class="string">"</span><span class="string">n9</span><span class="string">"</span>})
42.133 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> addDigit(String digit) {
42.134 - digit = digit.substring(<span class="number">1</span>);
42.135 - String v = Calculator.DISPLAY.getValue();
42.136 - <span class="keyword-directive">if</span> (getValue() == <span class="number">0.0</span>) {
42.137 - Calculator.DISPLAY.setValue(digit);
42.138 - } <span class="keyword-directive">else</span> {
42.139 - Calculator.DISPLAY.setValue(v + digit);
42.140 - }
42.141 - }
42.142 -
42.143 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> setValue(<span class="keyword-directive">double</span> v) {
42.144 - StringBuilder sb = <span class="keyword-directive">new</span> StringBuilder();
42.145 - sb.append(v);
42.146 - Calculator.DISPLAY.setValue(sb.toString());
42.147 - }
42.148 -
42.149 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> getValue() {
42.150 - <span class="keyword-directive">try</span> {
42.151 - <span class="keyword-directive">return</span> Double.parseDouble(Calculator.DISPLAY.getValue());
42.152 - } <span class="keyword-directive">catch</span> (NumberFormatException ex) {
42.153 - Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">err</span><span class="string">"</span>);
42.154 - <span class="keyword-directive">return</span> <span class="number">0.0</span>;
42.155 - }
42.156 - }
42.157 - }
42.158 -
42.159 - </pre>
42.160 - </body>
42.161 -</html>
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/javaquery/demo-calculator-dynamic/src/test/java/org/apidesign/bck2brwsr/demo/calc/CalcTest.java Wed Jan 23 12:53:23 2013 +0100
43.3 @@ -0,0 +1,46 @@
43.4 +/**
43.5 + * Back 2 Browser Bytecode Translator
43.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
43.7 + *
43.8 + * This program is free software: you can redistribute it and/or modify
43.9 + * it under the terms of the GNU General Public License as published by
43.10 + * the Free Software Foundation, version 2 of the License.
43.11 + *
43.12 + * This program is distributed in the hope that it will be useful,
43.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
43.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43.15 + * GNU General Public License for more details.
43.16 + *
43.17 + * You should have received a copy of the GNU General Public License
43.18 + * along with this program. Look for COPYING file in the top folder.
43.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
43.20 + */
43.21 +package org.apidesign.bck2brwsr.demo.calc;
43.22 +
43.23 +import static org.testng.Assert.*;
43.24 +import org.testng.annotations.BeforeMethod;
43.25 +import org.testng.annotations.Test;
43.26 +
43.27 +/** Demonstrating POJO testing of HTML page model.
43.28 + *
43.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
43.30 + */
43.31 +public class CalcTest {
43.32 + private Calculator model;
43.33 +
43.34 +
43.35 + @BeforeMethod
43.36 + public void initModel() {
43.37 + model = new Calculator().applyBindings();
43.38 + }
43.39 +
43.40 + @Test
43.41 + public void testSomeMethod() {
43.42 + model.setDisplay(10);
43.43 + Calc.applyOp(model, "plus");
43.44 + assertEquals(0.0, model.getDisplay(), "Cleared after pressing +");
43.45 + model.setDisplay(5);
43.46 + Calc.computeTheValue(model);
43.47 + assertEquals(15.0, model.getDisplay(), "Shows fifteen");
43.48 + }
43.49 +}
44.1 --- a/javaquery/demo-calculator/pom.xml Tue Jan 22 19:48:10 2013 +0100
44.2 +++ b/javaquery/demo-calculator/pom.xml Wed Jan 23 12:53:23 2013 +0100
44.3 @@ -42,7 +42,7 @@
44.4 <configuration>
44.5 <executable>xdg-open</executable>
44.6 <arguments>
44.7 - <argument>${project.build.directory}/classes/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml</argument>
44.8 + <argument>${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml</argument>
44.9 </arguments>
44.10 </configuration>
44.11 </plugin>
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
45.2 +++ b/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java Wed Jan 23 12:53:23 2013 +0100
45.3 @@ -0,0 +1,112 @@
45.4 +/**
45.5 + * Back 2 Browser Bytecode Translator
45.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
45.7 + *
45.8 + * This program is free software: you can redistribute it and/or modify
45.9 + * it under the terms of the GNU General Public License as published by
45.10 + * the Free Software Foundation, version 2 of the License.
45.11 + *
45.12 + * This program is distributed in the hope that it will be useful,
45.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
45.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45.15 + * GNU General Public License for more details.
45.16 + *
45.17 + * You should have received a copy of the GNU General Public License
45.18 + * along with this program. Look for COPYING file in the top folder.
45.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
45.20 + */
45.21 +package org.apidesign.bck2brwsr.demo.calc.staticcompilation;
45.22 +
45.23 +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
45.24 +import org.apidesign.bck2brwsr.htmlpage.api.On;
45.25 +import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;
45.26 +import org.apidesign.bck2brwsr.htmlpage.api.Page;
45.27 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
45.28 +
45.29 +/** HTML5 & Java demo showing the power of
45.30 + * <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation processors</a>
45.31 + * as well as other goodies.
45.32 + *
45.33 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
45.34 + */
45.35 +@Page(xhtml="Calculator.xhtml", properties = {
45.36 + @Property(name = "memory", type = double.class),
45.37 + @Property(name = "display", type = double.class),
45.38 + @Property(name = "operation", type = String.class),
45.39 + @Property(name = "hover", type = boolean.class)
45.40 +})
45.41 +public class Calc {
45.42 + static {
45.43 + new Calculator().applyBindings();
45.44 + }
45.45 +
45.46 + @On(event = CLICK, id="clear")
45.47 + static void clear(Calculator c) {
45.48 + c.setMemory(0);
45.49 + c.setOperation(null);
45.50 + c.setDisplay(0);
45.51 + }
45.52 +
45.53 + @On(event = CLICK, id= { "plus", "minus", "mul", "div" })
45.54 + static void applyOp(Calculator c, String op) {
45.55 + c.setMemory(c.getDisplay());
45.56 + c.setOperation(op);
45.57 + c.setDisplay(0);
45.58 + }
45.59 +
45.60 + @On(event = MOUSE_OVER, id= { "result" })
45.61 + static void attemptingIn(Calculator c, String op) {
45.62 + c.setHover(true);
45.63 + }
45.64 + @On(event = MOUSE_OUT, id= { "result" })
45.65 + static void attemptingOut(Calculator c, String op) {
45.66 + c.setHover(false);
45.67 + }
45.68 +
45.69 + @On(event = CLICK, id="result")
45.70 + static void computeTheValue(Calculator c) {
45.71 + c.setDisplay(compute(
45.72 + c.getOperation(),
45.73 + c.getMemory(),
45.74 + c.getDisplay()
45.75 + ));
45.76 + c.setMemory(0);
45.77 + }
45.78 +
45.79 + private static double compute(String op, double memory, double display) {
45.80 + switch (op) {
45.81 + case "plus": return memory + display;
45.82 + case "minus": return memory - display;
45.83 + case "mul": return memory * display;
45.84 + case "div": return memory / display;
45.85 + default: throw new IllegalStateException(op);
45.86 + }
45.87 + }
45.88 +
45.89 + @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"})
45.90 + static void addDigit(String digit, Calculator c) {
45.91 + digit = digit.substring(1);
45.92 +
45.93 + double v = c.getDisplay();
45.94 + if (v == 0.0) {
45.95 + c.setDisplay(Integer.parseInt(digit));
45.96 + } else {
45.97 + String txt = Double.toString(v);
45.98 + if (txt.endsWith(".0")) {
45.99 + txt = txt.substring(0, txt.length() - 2);
45.100 + }
45.101 + txt = txt + digit;
45.102 + c.setDisplay(Double.parseDouble(txt));
45.103 + }
45.104 + }
45.105 +
45.106 + @ComputedProperty
45.107 + public static String displayPreview(
45.108 + double display, boolean hover, double memory, String operation
45.109 + ) {
45.110 + if (!hover) {
45.111 + return "Type numbers and perform simple operations! Press '=' to get result.";
45.112 + }
45.113 + return "Attempt to compute " + memory + " " + operation + " " + display + " = " + compute(operation, memory, display);
45.114 + }
45.115 +}
46.1 --- a/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/mavenhtml/App.java Tue Jan 22 19:48:10 2013 +0100
46.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
46.3 @@ -1,89 +0,0 @@
46.4 -/**
46.5 - * Back 2 Browser Bytecode Translator
46.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
46.7 - *
46.8 - * This program is free software: you can redistribute it and/or modify
46.9 - * it under the terms of the GNU General Public License as published by
46.10 - * the Free Software Foundation, version 2 of the License.
46.11 - *
46.12 - * This program is distributed in the hope that it will be useful,
46.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
46.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46.15 - * GNU General Public License for more details.
46.16 - *
46.17 - * You should have received a copy of the GNU General Public License
46.18 - * along with this program. Look for COPYING file in the top folder.
46.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
46.20 - */
46.21 -package org.apidesign.bck2brwsr.mavenhtml;
46.22 -
46.23 -import org.apidesign.bck2brwsr.htmlpage.api.On;
46.24 -import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;
46.25 -import org.apidesign.bck2brwsr.htmlpage.api.Page;
46.26 -
46.27 -/** HTML5 & Java demo showing the power of
46.28 - * <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation processors</a>
46.29 - * as well as other goodies.
46.30 - *
46.31 - * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
46.32 - */
46.33 -@Page(xhtml="Calculator.xhtml")
46.34 -public class App {
46.35 - private static double memory;
46.36 - private static String operation;
46.37 -
46.38 - @On(event = CLICK, id="clear")
46.39 - static void clear() {
46.40 - memory = 0;
46.41 - operation = null;
46.42 - Calculator.DISPLAY.setValue("0");
46.43 - }
46.44 -
46.45 - @On(event = CLICK, id= { "plus", "minus", "mul", "div" })
46.46 - static void applyOp(String op) {
46.47 - memory = getValue();
46.48 - operation = op;
46.49 - Calculator.DISPLAY.setValue("0");
46.50 - }
46.51 -
46.52 - @On(event = CLICK, id="result")
46.53 - static void computeTheValue() {
46.54 - switch (operation) {
46.55 - case "plus": setValue(memory + getValue()); break;
46.56 - case "minus": setValue(memory - getValue()); break;
46.57 - case "mul": setValue(memory * getValue()); break;
46.58 - case "div": setValue(memory / getValue()); break;
46.59 - default: throw new IllegalStateException(operation);
46.60 - }
46.61 - }
46.62 -
46.63 - @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"})
46.64 - static void addDigit(String digit) {
46.65 - digit = digit.substring(1);
46.66 - String v = Calculator.DISPLAY.getValue();
46.67 - if (getValue() == 0.0) {
46.68 - Calculator.DISPLAY.setValue(digit);
46.69 - } else {
46.70 - Calculator.DISPLAY.setValue(v + digit);
46.71 - }
46.72 - }
46.73 -
46.74 - private static void setValue(double v) {
46.75 - StringBuilder sb = new StringBuilder();
46.76 - sb.append(v);
46.77 - if (sb.toString().endsWith(".0")) {
46.78 - final int l = sb.length();
46.79 - sb.delete(l - 2, l);
46.80 - }
46.81 - Calculator.DISPLAY.setValue(sb.toString());
46.82 - }
46.83 -
46.84 - private static double getValue() {
46.85 - try {
46.86 - return Double.parseDouble(Calculator.DISPLAY.getValue());
46.87 - } catch (NumberFormatException ex) {
46.88 - Calculator.DISPLAY.setValue("err");
46.89 - return 0.0;
46.90 - }
46.91 - }
46.92 -}
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Wed Jan 23 12:53:23 2013 +0100
47.3 @@ -0,0 +1,154 @@
47.4 +<?xml version="1.0" encoding="UTF-8"?>
47.5 +<!--
47.6 +
47.7 + Back 2 Browser Bytecode Translator
47.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
47.9 +
47.10 + This program is free software: you can redistribute it and/or modify
47.11 + it under the terms of the GNU General Public License as published by
47.12 + the Free Software Foundation, version 2 of the License.
47.13 +
47.14 + This program is distributed in the hope that it will be useful,
47.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
47.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47.17 + GNU General Public License for more details.
47.18 +
47.19 + You should have received a copy of the GNU General Public License
47.20 + along with this program. Look for COPYING file in the top folder.
47.21 + If not, see http://opensource.org/licenses/GPL-2.0.
47.22 +
47.23 +-->
47.24 +<!DOCTYPE html>
47.25 +<html xmlns="http://www.w3.org/1999/xhtml">
47.26 + <head>
47.27 + <title>Simple Calculator in HTML5 and Java</title>
47.28 +
47.29 + <style type="text/css">
47.30 + body {color: #ffffff; background-color: #121e31; font-family: Monospaced}
47.31 + pre {color: #ffffff; background-color: #121e31; font-family: Monospaced}
47.32 + table {color: #ffffff; background-color: #121e31; font-family: Monospaced}
47.33 + .string {color: #e2ce00}
47.34 + a {color: #e2ce00}
47.35 + .ST1 {color: #0000cc; font-family: Monospaced; font-weight: bold}
47.36 + .ST0 {color: #0000ff}
47.37 + .comment {color: #428bdd}
47.38 + .keyword-directive {color: #f8bb00}
47.39 + .tag {color: #f8bb00}
47.40 + .ST0 {color: #628fb5; background-color: #1b3450}
47.41 + .sgml-comment {color: #808080}
47.42 + .value {color: #99006b}
47.43 + .argument {color: #007c00}
47.44 + .sgml-declaration {color: #bf9221}
47.45 + </style>
47.46 + </head>
47.47 + <body>
47.48 + <h1>Java and HTML5 - Together at Last!</h1>
47.49 + <table border="0" cellspacing="2">
47.50 + <tbody>
47.51 + <tr>
47.52 + <td colspan="4"><input data-bind="value: display" value="0"
47.53 + style="text-align: right"/>
47.54 + </td>
47.55 + </tr>
47.56 + <tr>
47.57 + <td><button id="n1">1</button></td>
47.58 + <td><button id="n2">2</button></td>
47.59 + <td><button id="n3">3</button></td>
47.60 + <td><button id="plus">+</button></td>
47.61 + </tr>
47.62 + <tr>
47.63 + <td><button id="n4">4</button></td>
47.64 + <td><button id="n5">5</button></td>
47.65 + <td><button id="n6">6</button></td>
47.66 + <td><button id="minus">-</button></td>
47.67 + </tr>
47.68 + <tr>
47.69 + <td><button id="n7">7</button></td>
47.70 + <td><button id="n8">8</button></td>
47.71 + <td><button id="n9">9</button></td>
47.72 + <td><button id="mul">*</button></td>
47.73 + </tr>
47.74 + <tr>
47.75 + <td><button id="clear">C</button></td>
47.76 + <td><button id="n0">0</button></td>
47.77 + <td><button id="result">=</button></td>
47.78 + <td><button id="div">/</button></td>
47.79 + </tr>
47.80 + </tbody>
47.81 + </table>
47.82 + <div data-bind="text: displayPreview"></div>
47.83 + <script src="bootjava.js"/>
47.84 +
47.85 + <hr/>
47.86 + <pre>
47.87 + <span class="keyword-directive">package</span> org.apidesign.bck2brwsr.mavenhtml;
47.88 +
47.89 + <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.OnClick;
47.90 + <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.Page;
47.91 +
47.92 + <span class="comment">/**</span> <span class="comment">HTML5</span><span class="comment"> & </span><span class="comment">Java</span> <span class="comment">demo</span> <span class="comment">showing</span> <span class="comment">the</span> <span class="comment">power</span> <span class="comment">of</span> <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation processors</a>
47.93 + <span class="comment"> * </span><span class="comment">as</span> <span class="comment">well</span> <span class="comment">as</span> <span class="comment">other</span> <span class="comment">goodies</span><span class="comment">, including type-safe association between</span>
47.94 + <span class="comment"> * </span><span class="comment">an XHTML page and Java.</span>
47.95 + <span class="comment"> * </span>
47.96 + <span class="comment"> * </span><span class="ST1">@author</span> <span class="comment">Jaroslav</span> <span class="comment">Tulach</span> <span class="ST0"><jaroslav.tulach@apidesign.org></span>
47.97 + <span class="comment">*/</span>
47.98 + @Page(xhtml=<span class="string">"</span><span class="string">Calculator.xhtml</span><span class="string">"</span>)
47.99 + <span class="keyword-directive">public</span> <span class="keyword-directive">class</span> App {
47.100 + <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> memory;
47.101 + <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> String operation;
47.102 +
47.103 + @OnClick(id=<span class="string">"</span><span class="string">clear</span><span class="string">"</span>)
47.104 + <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> clear() {
47.105 + memory = <span class="number">0</span>;
47.106 + operation = <span class="keyword-directive">null</span>;
47.107 + Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
47.108 + }
47.109 +
47.110 + @OnClick(id= { <span class="string">"</span><span class="string">plus</span><span class="string">"</span>, <span class="string">"</span><span class="string">minus</span><span class="string">"</span>, <span class="string">"</span><span class="string">mul</span><span class="string">"</span>, <span class="string">"</span><span class="string">div</span><span class="string">"</span> })
47.111 + <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> applyOp(String op) {
47.112 + memory = getValue();
47.113 + operation = op;
47.114 + Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
47.115 + }
47.116 +
47.117 + @OnClick(id=<span class="string">"</span><span class="string">result</span><span class="string">"</span>)
47.118 + <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> computeTheValue() {
47.119 + <span class="keyword-directive">switch</span> (operation) {
47.120 + <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">plus</span><span class="string">"</span>: setValue(memory + getValue()); <span class="keyword-directive">break</span>;
47.121 + <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">minus</span><span class="string">"</span>: setValue(memory - getValue()); <span class="keyword-directive">break</span>;
47.122 + <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">mul</span><span class="string">"</span>: setValue(memory * getValue()); <span class="keyword-directive">break</span>;
47.123 + <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">div</span><span class="string">"</span>: setValue(memory / getValue()); <span class="keyword-directive">break</span>;
47.124 + <span class="keyword-directive">default</span>: <span class="keyword-directive">throw</span> <span class="keyword-directive">new</span> IllegalStateException(operation);
47.125 + }
47.126 + }
47.127 +
47.128 + @OnClick(id={<span class="string">"</span><span class="string">n0</span><span class="string">"</span>, <span class="string">"</span><span class="string">n1</span><span class="string">"</span>, <span class="string">"</span><span class="string">n2</span><span class="string">"</span>, <span class="string">"</span><span class="string">n3</span><span class="string">"</span>, <span class="string">"</span><span class="string">n4</span><span class="string">"</span>, <span class="string">"</span><span class="string">n5</span><span class="string">"</span>, <span class="string">"</span><span class="string">n6</span><span class="string">"</span>, <span class="string">"</span><span class="string">n7</span><span class="string">"</span>, <span class="string">"</span><span class="string">n8</span><span class="string">"</span>, <span class="string">"</span><span class="string">n9</span><span class="string">"</span>})
47.129 + <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> addDigit(String digit) {
47.130 + digit = digit.substring(<span class="number">1</span>);
47.131 + String v = Calculator.DISPLAY.getValue();
47.132 + <span class="keyword-directive">if</span> (getValue() == <span class="number">0.0</span>) {
47.133 + Calculator.DISPLAY.setValue(digit);
47.134 + } <span class="keyword-directive">else</span> {
47.135 + Calculator.DISPLAY.setValue(v + digit);
47.136 + }
47.137 + }
47.138 +
47.139 + <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> setValue(<span class="keyword-directive">double</span> v) {
47.140 + StringBuilder sb = <span class="keyword-directive">new</span> StringBuilder();
47.141 + sb.append(v);
47.142 + Calculator.DISPLAY.setValue(sb.toString());
47.143 + }
47.144 +
47.145 + <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> getValue() {
47.146 + <span class="keyword-directive">try</span> {
47.147 + <span class="keyword-directive">return</span> Double.parseDouble(Calculator.DISPLAY.getValue());
47.148 + } <span class="keyword-directive">catch</span> (NumberFormatException ex) {
47.149 + Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">err</span><span class="string">"</span>);
47.150 + <span class="keyword-directive">return</span> <span class="number">0.0</span>;
47.151 + }
47.152 + }
47.153 + }
47.154 +
47.155 + </pre>
47.156 + </body>
47.157 +</html>
48.1 --- a/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/mavenhtml/Calculator.xhtml Tue Jan 22 19:48:10 2013 +0100
48.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
48.3 @@ -1,154 +0,0 @@
48.4 -<?xml version="1.0" encoding="UTF-8"?>
48.5 -<!--
48.6 -
48.7 - Back 2 Browser Bytecode Translator
48.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
48.9 -
48.10 - This program is free software: you can redistribute it and/or modify
48.11 - it under the terms of the GNU General Public License as published by
48.12 - the Free Software Foundation, version 2 of the License.
48.13 -
48.14 - This program is distributed in the hope that it will be useful,
48.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
48.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48.17 - GNU General Public License for more details.
48.18 -
48.19 - You should have received a copy of the GNU General Public License
48.20 - along with this program. Look for COPYING file in the top folder.
48.21 - If not, see http://opensource.org/licenses/GPL-2.0.
48.22 -
48.23 --->
48.24 -<!DOCTYPE html>
48.25 -<html xmlns="http://www.w3.org/1999/xhtml">
48.26 - <head>
48.27 - <title>Simple Calculator in HTML5 and Java</title>
48.28 -
48.29 - <style type="text/css">
48.30 - body {color: #ffffff; background-color: #121e31; font-family: Monospaced}
48.31 - pre {color: #ffffff; background-color: #121e31; font-family: Monospaced}
48.32 - table {color: #ffffff; background-color: #121e31; font-family: Monospaced}
48.33 - .string {color: #e2ce00}
48.34 - a {color: #e2ce00}
48.35 - .ST1 {color: #0000cc; font-family: Monospaced; font-weight: bold}
48.36 - .ST0 {color: #0000ff}
48.37 - .comment {color: #428bdd}
48.38 - .keyword-directive {color: #f8bb00}
48.39 - .tag {color: #f8bb00}
48.40 - .ST0 {color: #628fb5; background-color: #1b3450}
48.41 - .sgml-comment {color: #808080}
48.42 - .value {color: #99006b}
48.43 - .argument {color: #007c00}
48.44 - .sgml-declaration {color: #bf9221}
48.45 - </style>
48.46 - </head>
48.47 - <body>
48.48 - <h1>Java and HTML5 - Together at Last!</h1>
48.49 - <table border="0" cellspacing="2">
48.50 - <tbody>
48.51 - <tr>
48.52 - <td colspan="4"><input id="display" value="0"
48.53 - style="text-align: right"/>
48.54 - </td>
48.55 - </tr>
48.56 - <tr>
48.57 - <td><button id="n1">1</button></td>
48.58 - <td><button id="n2">2</button></td>
48.59 - <td><button id="n3">3</button></td>
48.60 - <td><button id="plus">+</button></td>
48.61 - </tr>
48.62 - <tr>
48.63 - <td><button id="n4">4</button></td>
48.64 - <td><button id="n5">5</button></td>
48.65 - <td><button id="n6">6</button></td>
48.66 - <td><button id="minus">-</button></td>
48.67 - </tr>
48.68 - <tr>
48.69 - <td><button id="n7">7</button></td>
48.70 - <td><button id="n8">8</button></td>
48.71 - <td><button id="n9">9</button></td>
48.72 - <td><button id="mul">*</button></td>
48.73 - </tr>
48.74 - <tr>
48.75 - <td><button id="clear">C</button></td>
48.76 - <td><button id="n0">0</button></td>
48.77 - <td><button id="result">=</button></td>
48.78 - <td><button id="div">/</button></td>
48.79 - </tr>
48.80 - </tbody>
48.81 - </table>
48.82 -
48.83 - <script src="bootjava.js"/>
48.84 -
48.85 - <hr/>
48.86 - <pre>
48.87 - <span class="keyword-directive">package</span> org.apidesign.bck2brwsr.mavenhtml;
48.88 -
48.89 - <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.OnClick;
48.90 - <span class="keyword-directive">import</span> org.apidesign.bck2brwsr.htmlpage.api.Page;
48.91 -
48.92 - <span class="comment">/**</span> <span class="comment">HTML5</span><span class="comment"> & </span><span class="comment">Java</span> <span class="comment">demo</span> <span class="comment">showing</span> <span class="comment">the</span> <span class="comment">power</span> <span class="comment">of</span> <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation processors</a>
48.93 - <span class="comment"> * </span><span class="comment">as</span> <span class="comment">well</span> <span class="comment">as</span> <span class="comment">other</span> <span class="comment">goodies</span><span class="comment">, including type-safe association between</span>
48.94 - <span class="comment"> * </span><span class="comment">an XHTML page and Java.</span>
48.95 - <span class="comment"> * </span>
48.96 - <span class="comment"> * </span><span class="ST1">@author</span> <span class="comment">Jaroslav</span> <span class="comment">Tulach</span> <span class="ST0"><jaroslav.tulach@apidesign.org></span>
48.97 - <span class="comment">*/</span>
48.98 - @Page(xhtml=<span class="string">"</span><span class="string">Calculator.xhtml</span><span class="string">"</span>)
48.99 - <span class="keyword-directive">public</span> <span class="keyword-directive">class</span> App {
48.100 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> memory;
48.101 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> String operation;
48.102 -
48.103 - @OnClick(id=<span class="string">"</span><span class="string">clear</span><span class="string">"</span>)
48.104 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> clear() {
48.105 - memory = <span class="number">0</span>;
48.106 - operation = <span class="keyword-directive">null</span>;
48.107 - Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
48.108 - }
48.109 -
48.110 - @OnClick(id= { <span class="string">"</span><span class="string">plus</span><span class="string">"</span>, <span class="string">"</span><span class="string">minus</span><span class="string">"</span>, <span class="string">"</span><span class="string">mul</span><span class="string">"</span>, <span class="string">"</span><span class="string">div</span><span class="string">"</span> })
48.111 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> applyOp(String op) {
48.112 - memory = getValue();
48.113 - operation = op;
48.114 - Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">0</span><span class="string">"</span>);
48.115 - }
48.116 -
48.117 - @OnClick(id=<span class="string">"</span><span class="string">result</span><span class="string">"</span>)
48.118 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> computeTheValue() {
48.119 - <span class="keyword-directive">switch</span> (operation) {
48.120 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">plus</span><span class="string">"</span>: setValue(memory + getValue()); <span class="keyword-directive">break</span>;
48.121 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">minus</span><span class="string">"</span>: setValue(memory - getValue()); <span class="keyword-directive">break</span>;
48.122 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">mul</span><span class="string">"</span>: setValue(memory * getValue()); <span class="keyword-directive">break</span>;
48.123 - <span class="keyword-directive">case</span> <span class="string">"</span><span class="string">div</span><span class="string">"</span>: setValue(memory / getValue()); <span class="keyword-directive">break</span>;
48.124 - <span class="keyword-directive">default</span>: <span class="keyword-directive">throw</span> <span class="keyword-directive">new</span> IllegalStateException(operation);
48.125 - }
48.126 - }
48.127 -
48.128 - @OnClick(id={<span class="string">"</span><span class="string">n0</span><span class="string">"</span>, <span class="string">"</span><span class="string">n1</span><span class="string">"</span>, <span class="string">"</span><span class="string">n2</span><span class="string">"</span>, <span class="string">"</span><span class="string">n3</span><span class="string">"</span>, <span class="string">"</span><span class="string">n4</span><span class="string">"</span>, <span class="string">"</span><span class="string">n5</span><span class="string">"</span>, <span class="string">"</span><span class="string">n6</span><span class="string">"</span>, <span class="string">"</span><span class="string">n7</span><span class="string">"</span>, <span class="string">"</span><span class="string">n8</span><span class="string">"</span>, <span class="string">"</span><span class="string">n9</span><span class="string">"</span>})
48.129 - <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> addDigit(String digit) {
48.130 - digit = digit.substring(<span class="number">1</span>);
48.131 - String v = Calculator.DISPLAY.getValue();
48.132 - <span class="keyword-directive">if</span> (getValue() == <span class="number">0.0</span>) {
48.133 - Calculator.DISPLAY.setValue(digit);
48.134 - } <span class="keyword-directive">else</span> {
48.135 - Calculator.DISPLAY.setValue(v + digit);
48.136 - }
48.137 - }
48.138 -
48.139 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">void</span> setValue(<span class="keyword-directive">double</span> v) {
48.140 - StringBuilder sb = <span class="keyword-directive">new</span> StringBuilder();
48.141 - sb.append(v);
48.142 - Calculator.DISPLAY.setValue(sb.toString());
48.143 - }
48.144 -
48.145 - <span class="keyword-directive">private</span> <span class="keyword-directive">static</span> <span class="keyword-directive">double</span> getValue() {
48.146 - <span class="keyword-directive">try</span> {
48.147 - <span class="keyword-directive">return</span> Double.parseDouble(Calculator.DISPLAY.getValue());
48.148 - } <span class="keyword-directive">catch</span> (NumberFormatException ex) {
48.149 - Calculator.DISPLAY.setValue(<span class="string">"</span><span class="string">err</span><span class="string">"</span>);
48.150 - <span class="keyword-directive">return</span> <span class="number">0.0</span>;
48.151 - }
48.152 - }
48.153 - }
48.154 -
48.155 - </pre>
48.156 - </body>
48.157 -</html>
49.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Tue Jan 22 19:48:10 2013 +0100
49.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Wed Jan 23 12:53:23 2013 +0100
49.3 @@ -56,7 +56,7 @@
49.4 */
49.5 final class Bck2BrwsrLauncher extends Launcher implements Closeable {
49.6 private static final Logger LOG = Logger.getLogger(Bck2BrwsrLauncher.class.getName());
49.7 - private static final MethodInvocation END = new MethodInvocation(null, null);
49.8 + private static final MethodInvocation END = new MethodInvocation(null, null, null);
49.9 private Set<ClassLoader> loaders = new LinkedHashSet<>();
49.10 private Set<Bck2Brwsr.Resources> xRes = new LinkedHashSet<>();
49.11 private BlockingQueue<MethodInvocation> methods = new LinkedBlockingQueue<>();
49.12 @@ -72,9 +72,9 @@
49.13 }
49.14
49.15 @Override
49.16 - public MethodInvocation addMethod(Class<?> clazz, String method) throws IOException {
49.17 + MethodInvocation addMethod(Class<?> clazz, String method, String html) throws IOException {
49.18 loaders.add(clazz.getClassLoader());
49.19 - MethodInvocation c = new MethodInvocation(clazz.getName(), method);
49.20 + MethodInvocation c = new MethodInvocation(clazz.getName(), method, html);
49.21 methods.add(c);
49.22 try {
49.23 c.await(timeOut);
49.24 @@ -187,7 +187,13 @@
49.25 + "className: '" + cn + "', "
49.26 + "methodName: '" + mn + "', "
49.27 + "request: " + cnt
49.28 - + "}");
49.29 + );
49.30 + if (mi.html != null) {
49.31 + response.getWriter().write(", html: '");
49.32 + response.getWriter().write(encodeJSON(mi.html));
49.33 + response.getWriter().write("'");
49.34 + }
49.35 + response.getWriter().write("}");
49.36 cnt++;
49.37 }
49.38 }, "/data");
49.39 @@ -195,6 +201,22 @@
49.40 this.brwsr = launchServerAndBrwsr(server, "/execute");
49.41 }
49.42
49.43 + private static String encodeJSON(String in) {
49.44 + StringBuilder sb = new StringBuilder();
49.45 + for (int i = 0; i < in.length(); i++) {
49.46 + char ch = in.charAt(i);
49.47 + if (ch < 32 || ch == '\'' || ch == '"') {
49.48 + sb.append("\\u");
49.49 + String hs = "0000" + Integer.toHexString(ch);
49.50 + hs = hs.substring(hs.length() - 4);
49.51 + sb.append(hs);
49.52 + } else {
49.53 + sb.append(ch);
49.54 + }
49.55 + }
49.56 + return sb.toString();
49.57 + }
49.58 +
49.59 @Override
49.60 public void shutdown() throws IOException {
49.61 methods.offer(END);
49.62 @@ -229,12 +251,12 @@
49.63 if (ch == -1) {
49.64 break;
49.65 }
49.66 - if (ch == '$') {
49.67 + if (ch == '$' && params.length > 0) {
49.68 int cnt = is.read() - '0';
49.69 if (cnt == 'U' - '0') {
49.70 os.write(baseURL.getBytes());
49.71 }
49.72 - if (cnt < params.length) {
49.73 + if (cnt >= 0 && cnt < params.length) {
49.74 os.write(params[cnt].getBytes());
49.75 }
49.76 } else {
49.77 @@ -252,11 +274,17 @@
49.78 LOG.log(Level.INFO, "Showing {0}", uri);
49.79 if (cmd == null) {
49.80 try {
49.81 + LOG.log(Level.INFO, "Trying Desktop.browse on {0} {2} by {1}", new Object[] {
49.82 + System.getProperty("java.vm.name"),
49.83 + System.getProperty("java.vm.vendor"),
49.84 + System.getProperty("java.vm.version"),
49.85 + });
49.86 java.awt.Desktop.getDesktop().browse(uri);
49.87 LOG.log(Level.INFO, "Desktop.browse successfully finished");
49.88 return null;
49.89 } catch (UnsupportedOperationException ex) {
49.90 - LOG.log(Level.INFO, "Desktop.browse not supported", ex);
49.91 + LOG.log(Level.INFO, "Desktop.browse not supported: {0}", ex.getMessage());
49.92 + LOG.log(Level.FINE, null, ex);
49.93 }
49.94 }
49.95 {
49.96 @@ -366,7 +394,7 @@
49.97 public Page(Res res, String resource, String... args) {
49.98 this.res = res;
49.99 this.resource = resource;
49.100 - this.args = args;
49.101 + this.args = args.length == 0 ? new String[] { "$0" } : args;
49.102 }
49.103
49.104 @Override
49.105 @@ -378,17 +406,20 @@
49.106 r = r.substring(1);
49.107 }
49.108 }
49.109 + String[] replace = {};
49.110 if (r.endsWith(".html")) {
49.111 response.setContentType("text/html");
49.112 LOG.info("Content type text/html");
49.113 + replace = args;
49.114 }
49.115 if (r.endsWith(".xhtml")) {
49.116 response.setContentType("application/xhtml+xml");
49.117 LOG.info("Content type application/xhtml+xml");
49.118 + replace = args;
49.119 }
49.120 OutputStream os = response.getOutputStream();
49.121 try (InputStream is = res.get(r)) {
49.122 - copyStream(is, os, request.getRequestURL().toString(), args);
49.123 + copyStream(is, os, request.getRequestURL().toString(), replace);
49.124 } catch (IOException ex) {
49.125 response.setDetailMessage(ex.getLocalizedMessage());
49.126 response.setError();
50.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Console.java Tue Jan 22 19:48:10 2013 +0100
50.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Console.java Wed Jan 23 12:53:23 2013 +0100
50.3 @@ -31,11 +31,8 @@
50.4 * @author Jaroslav Tulach <jtulach@netbeans.org>
50.5 */
50.6 public class Console {
50.7 - public static String welcome() {
50.8 - return "HellofromBck2Brwsr";
50.9 - }
50.10 - public static String multiply() {
50.11 - return String.valueOf(Integer.MAX_VALUE / 2 + Integer.MAX_VALUE);
50.12 + static {
50.13 + turnAssetionStatusOn();
50.14 }
50.15
50.16 @JavaScriptBody(args = {"id", "attr"}, body =
50.17 @@ -50,7 +47,7 @@
50.18 private static native void closeWindow();
50.19
50.20 private static void log(String newText) {
50.21 - String id = "result";
50.22 + String id = "bck2brwsr.result";
50.23 String attr = "value";
50.24 setAttr(id, attr, getAttr(id, attr) + "\n" + newText);
50.25 setAttr(id, "scrollTop", getAttr(id, "scrollHeight"));
50.26 @@ -60,38 +57,74 @@
50.27 String clazz = (String) getAttr("clazz", "value");
50.28 String method = (String) getAttr("method", "value");
50.29 Object res = invokeMethod(clazz, method);
50.30 - setAttr("result", "value", res);
50.31 + setAttr("bck2brwsr.result", "value", res);
50.32 + }
50.33 +
50.34 + @JavaScriptBody(args = { "url", "callback", "arr" }, body = ""
50.35 + + "var request = new XMLHttpRequest();\n"
50.36 + + "request.open('GET', url, true);\n"
50.37 + + "request.onreadystatechange = function() {\n"
50.38 + + " if (this.readyState!==4) return;\n"
50.39 + + " arr[0] = this.responseText;\n"
50.40 + + " callback.run__V();\n"
50.41 + + "};"
50.42 + + "request.send();"
50.43 + )
50.44 + private static native void loadText(String url, Runnable callback, String[] arr) throws IOException;
50.45 +
50.46 + public static void harness(String url) throws IOException {
50.47 + log("Connecting to " + url);
50.48 + Request r = new Request(url);
50.49 }
50.50
50.51 - public static void harness(String url) {
50.52 - log("Connecting to " + url);
50.53 - try {
50.54 - URL u = new URL(url);
50.55 - for (;;) {
50.56 - String data = (String) u.getContent(new Class[] { String.class });
50.57 + private static class Request implements Runnable {
50.58 + private final String[] arr = { null };
50.59 + private final String url;
50.60 +
50.61 + private Request(String url) throws IOException {
50.62 + this.url = url;
50.63 + loadText(url, this, arr);
50.64 + }
50.65 +
50.66 + @Override
50.67 + public void run() {
50.68 + try {
50.69 + String data = arr[0];
50.70 log("\nGot \"" + data + "\"");
50.71 +
50.72 + if (data == null) {
50.73 + log("Some error exiting");
50.74 + closeWindow();
50.75 + return;
50.76 + }
50.77 +
50.78 if (data.isEmpty()) {
50.79 log("No data, exiting");
50.80 closeWindow();
50.81 - break;
50.82 + return;
50.83 }
50.84
50.85 Case c = Case.parseData(data);
50.86 + if (c.getHtmlFragment() != null) {
50.87 + setAttr("bck2brwsr.fragment", "innerHTML", c.getHtmlFragment());
50.88 + }
50.89 log("Invoking " + c.getClassName() + '.' + c.getMethodName() + " as request: " + c.getRequestId());
50.90
50.91 Object result = invokeMethod(c.getClassName(), c.getMethodName());
50.92
50.93 + setAttr("bck2brwsr.fragment", "innerHTML", "");
50.94 log("Result: " + result);
50.95
50.96 result = encodeURL("" + result);
50.97
50.98 log("Sending back: " + url + "?request=" + c.getRequestId() + "&result=" + result);
50.99 - u = new URL(url + "?request=" + c.getRequestId() + "&result=" + result);
50.100 + String u = url + "?request=" + c.getRequestId() + "&result=" + result;
50.101 +
50.102 + loadText(u, this, arr);
50.103 +
50.104 + } catch (Exception ex) {
50.105 + log(ex.getMessage());
50.106 }
50.107 -
50.108 -
50.109 - } catch (Exception ex) {
50.110 - log(ex.getMessage());
50.111 }
50.112 }
50.113
50.114 @@ -167,7 +200,7 @@
50.115 } else {
50.116 res = found.invoke(c.newInstance());
50.117 }
50.118 - } catch (Exception ex) {
50.119 + } catch (Throwable ex) {
50.120 res = ex.getClass().getName() + ":" + ex.getMessage();
50.121 }
50.122 } else {
50.123 @@ -175,6 +208,10 @@
50.124 }
50.125 return res;
50.126 }
50.127 +
50.128 + @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
50.129 + private static void turnAssetionStatusOn() {
50.130 + }
50.131
50.132 private static final class Case {
50.133 private final Object data;
50.134 @@ -198,11 +235,19 @@
50.135 public String getRequestId() {
50.136 return value("request", data);
50.137 }
50.138 +
50.139 + public String getHtmlFragment() {
50.140 + return value("html", data);
50.141 + }
50.142
50.143 @JavaScriptBody(args = "s", body = "return eval('(' + s + ')');")
50.144 private static native Object toJSON(String s);
50.145
50.146 - @JavaScriptBody(args = {"p", "d"}, body = "return d[p].toString();")
50.147 + @JavaScriptBody(args = {"p", "d"}, body =
50.148 + "var v = d[p];\n"
50.149 + + "if (typeof v === 'undefined') return null;\n"
50.150 + + "return v.toString();"
50.151 + )
50.152 private static native String value(String p, Object d);
50.153 }
50.154 }
51.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Tue Jan 22 19:48:10 2013 +0100
51.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Wed Jan 23 12:53:23 2013 +0100
51.3 @@ -42,10 +42,9 @@
51.4 private Object console;
51.5
51.6
51.7 - @Override
51.8 - public MethodInvocation addMethod(Class<?> clazz, String method) {
51.9 + @Override MethodInvocation addMethod(Class<?> clazz, String method, String html) {
51.10 loaders.add(clazz.getClassLoader());
51.11 - MethodInvocation mi = new MethodInvocation(clazz.getName(), method);
51.12 + MethodInvocation mi = new MethodInvocation(clazz.getName(), method, html);
51.13 try {
51.14 mi.result(code.invokeMethod(
51.15 console,
52.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Tue Jan 22 19:48:10 2013 +0100
52.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Wed Jan 23 12:53:23 2013 +0100
52.3 @@ -32,12 +32,12 @@
52.4 Launcher() {
52.5 }
52.6
52.7 - abstract MethodInvocation addMethod(Class<?> clazz, String method) throws IOException;
52.8 + abstract MethodInvocation addMethod(Class<?> clazz, String method, String html) throws IOException;
52.9
52.10 public abstract void initialize() throws IOException;
52.11 public abstract void shutdown() throws IOException;
52.12 - public MethodInvocation invokeMethod(Class<?> clazz, String method) throws IOException {
52.13 - return addMethod(clazz, method);
52.14 + public MethodInvocation invokeMethod(Class<?> clazz, String method, String html) throws IOException {
52.15 + return addMethod(clazz, method, html);
52.16 }
52.17
52.18
53.1 --- a/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/MethodInvocation.java Tue Jan 22 19:48:10 2013 +0100
53.2 +++ b/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/MethodInvocation.java Wed Jan 23 12:53:23 2013 +0100
53.3 @@ -28,12 +28,14 @@
53.4 final CountDownLatch wait = new CountDownLatch(1);
53.5 final String className;
53.6 final String methodName;
53.7 + final String html;
53.8 private String result;
53.9 private Throwable exception;
53.10
53.11 - MethodInvocation(String className, String methodName) {
53.12 + MethodInvocation(String className, String methodName, String html) {
53.13 this.className = className;
53.14 this.methodName = methodName;
53.15 + this.html = html;
53.16 }
53.17
53.18 void await(long timeOut) throws InterruptedException {
54.1 --- a/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/console.xhtml Tue Jan 22 19:48:10 2013 +0100
54.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
54.3 @@ -1,52 +0,0 @@
54.4 -<?xml version="1.0" encoding="UTF-8"?>
54.5 -<!--
54.6 -
54.7 - Back 2 Browser Bytecode Translator
54.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
54.9 -
54.10 - This program is free software: you can redistribute it and/or modify
54.11 - it under the terms of the GNU General Public License as published by
54.12 - the Free Software Foundation, version 2 of the License.
54.13 -
54.14 - This program is distributed in the hope that it will be useful,
54.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
54.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54.17 - GNU General Public License for more details.
54.18 -
54.19 - You should have received a copy of the GNU General Public License
54.20 - along with this program. Look for COPYING file in the top folder.
54.21 - If not, see http://opensource.org/licenses/GPL-2.0.
54.22 -
54.23 --->
54.24 -<!DOCTYPE html>
54.25 -<html xmlns="http://www.w3.org/1999/xhtml">
54.26 - <head>
54.27 - <title>Bck2Brwsr Launcher</title>
54.28 - </head>
54.29 - <body>
54.30 - <script src="/bck2brwsr.js"></script>
54.31 - <script src="/vm.js"></script>
54.32 -
54.33 - <h1>Bck2Browser Console Launcher</h1>
54.34 -
54.35 - Class Name:
54.36 - <input id="clazz" value="$0"/>
54.37 - <br/>
54.38 - Method Name:
54.39 -
54.40 - <input id="method" value="$1"/>
54.41 - <br/>
54.42 -
54.43 - <button onclick="vm.loadClass('org.apidesign.bck2brwsr.launcher.Console').execute__V();">Execute!</button>
54.44 -
54.45 - <hr/>
54.46 - <textarea id="result" rows="10" cols="80" disabled="">
54.47 - </textarea>
54.48 -
54.49 - <script type="text/javascript">
54.50 - if ($2) {
54.51 - vm.loadClass('org.apidesign.bck2brwsr.launcher.Console').execute__V();
54.52 - }
54.53 - </script>
54.54 - </body>
54.55 -</html>
55.1 --- a/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Tue Jan 22 19:48:10 2013 +0100
55.2 +++ b/launcher/src/main/resources/org/apidesign/bck2brwsr/launcher/harness.xhtml Wed Jan 23 12:53:23 2013 +0100
55.3 @@ -27,10 +27,12 @@
55.4 <script src="/bck2brwsr.js"></script>
55.5 <script src="/vm.js"></script>
55.6
55.7 - <h1>Bck2Browser Execution Harness</h1>
55.8 + <h1>Bck2Brwsr Execution Harness</h1>
55.9
55.10 - <textarea id="result" rows="25" style="width: 100%;" disabled="">
55.11 + <textarea id="bck2brwsr.result" rows="25" style="width: 100%;" disabled="">
55.12 </textarea>
55.13 +
55.14 + <div id="bck2brwsr.fragment"/>
55.15
55.16 <script type="text/javascript">
55.17 vm.loadClass('org.apidesign.bck2brwsr.launcher.Console').harness__VLjava_lang_String_2('$U/../data');
56.1 --- a/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrswrMojo.java Tue Jan 22 19:48:10 2013 +0100
56.2 +++ b/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrswrMojo.java Wed Jan 23 12:53:23 2013 +0100
56.3 @@ -82,7 +82,10 @@
56.4 List<URL> arr = new ArrayList<URL>();
56.5 arr.add(root.toURI().toURL());
56.6 for (Artifact a : deps) {
56.7 - arr.add(a.getFile().toURI().toURL());
56.8 + final File f = a.getFile();
56.9 + if (f != null) {
56.10 + arr.add(f.toURI().toURL());
56.11 + }
56.12 }
56.13 return new URLClassLoader(arr.toArray(new URL[0]), BrswrMojo.class.getClassLoader());
56.14 }
57.1 --- a/mojo/src/main/resources/META-INF/maven/archetype-metadata.xml Tue Jan 22 19:48:10 2013 +0100
57.2 +++ b/mojo/src/main/resources/META-INF/maven/archetype-metadata.xml Wed Jan 23 12:53:23 2013 +0100
57.3 @@ -23,7 +23,7 @@
57.4 <fileSet filtered="true" packaged="true">
57.5 <directory>src/main/java</directory>
57.6 <includes>
57.7 - <include>**/*.java</include>
57.8 + <include>**/App.java</include>
57.9 </includes>
57.10 </fileSet>
57.11 <fileSet filtered="true" packaged="true">
57.12 @@ -32,6 +32,12 @@
57.13 <include>**/*.xhtml</include>
57.14 </includes>
57.15 </fileSet>
57.16 + <fileSet filtered="true" packaged="true">
57.17 + <directory>src/test/java</directory>
57.18 + <includes>
57.19 + <include>**/*Test.java</include>
57.20 + </includes>
57.21 + </fileSet>
57.22 <fileSet filtered="false" packaged="false">
57.23 <directory></directory>
57.24 <includes>
58.1 --- a/mojo/src/main/resources/archetype-resources/pom.xml Tue Jan 22 19:48:10 2013 +0100
58.2 +++ b/mojo/src/main/resources/archetype-resources/pom.xml Wed Jan 23 12:53:23 2013 +0100
58.3 @@ -53,5 +53,17 @@
58.4 <artifactId>javaquery.api</artifactId>
58.5 <version>0.3-SNAPSHOT</version>
58.6 </dependency>
58.7 + <dependency>
58.8 + <groupId>org.testng</groupId>
58.9 + <artifactId>testng</artifactId>
58.10 + <version>6.5.2</version>
58.11 + <scope>test</scope>
58.12 + </dependency>
58.13 + <dependency>
58.14 + <groupId>${project.groupId}</groupId>
58.15 + <artifactId>vmtest</artifactId>
58.16 + <version>0.3-SNAPSHOT</version>
58.17 + <scope>test</scope>
58.18 + </dependency>
58.19 </dependencies>
58.20 </project>
59.1 --- a/mojo/src/main/resources/archetype-resources/src/main/java/App.java Tue Jan 22 19:48:10 2013 +0100
59.2 +++ b/mojo/src/main/resources/archetype-resources/src/main/java/App.java Wed Jan 23 12:53:23 2013 +0100
59.3 @@ -3,15 +3,32 @@
59.4 import org.apidesign.bck2brwsr.htmlpage.api.*;
59.5 import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;
59.6 import org.apidesign.bck2brwsr.htmlpage.api.Page;
59.7 +import org.apidesign.bck2brwsr.htmlpage.api.Property;
59.8 +import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
59.9
59.10 /** Edit the index.xhtml file. Use 'id' to name certain HTML elements.
59.11 * Use this class to define behavior of the elements.
59.12 */
59.13 -@Page(xhtml="index.xhtml", className="Index")
59.14 +@Page(xhtml="index.xhtml", className="Index", properties={
59.15 + @Property(name="name", type=String.class)
59.16 +})
59.17 public class App {
59.18 + static {
59.19 + Index model = new Index();
59.20 + model.setName("World");
59.21 + model.applyBindings();
59.22 + }
59.23 +
59.24 @On(event = CLICK, id="hello")
59.25 - static void hello() {
59.26 - Index.HELLO.setDisabled(true);
59.27 - Element.alert("Hello World!");
59.28 + static void hello(Index m) {
59.29 + GraphicsContext g = m.CANVAS.getContext();
59.30 + g.clearRect(0, 0, 1000, 1000);
59.31 + g.setFont("italic 40px Calibri");
59.32 + g.fillText(m.getHelloMessage(), 10, 40);
59.33 + }
59.34 +
59.35 + @ComputedProperty
59.36 + static String helloMessage(String name) {
59.37 + return "Hello " + name + "!";
59.38 }
59.39 }
60.1 --- a/mojo/src/main/resources/archetype-resources/src/main/resources/index.xhtml Tue Jan 22 19:48:10 2013 +0100
60.2 +++ b/mojo/src/main/resources/archetype-resources/src/main/resources/index.xhtml Wed Jan 23 12:53:23 2013 +0100
60.3 @@ -5,12 +5,18 @@
60.4 <title>Bck2Brwsr's Hello World</title>
60.5 </head>
60.6 <body>
60.7 - <button id="hello">Hello World!</button>
60.8 + <h1 data-bind="text: helloMessage">Loading Bck2Brwsr's Hello World...</h1>
60.9 + Your name: <input id='input' data-bind="value: name, valueUpdate: 'afterkeydown'"></input>
60.10 + <button id="hello">Say Hello!</button>
60.11 + <p>
60.12 + <canvas id="canvas" width="300" height="50">
60.13 + </canvas>
60.14 + </p>
60.15
60.16 <script src="/bck2brwsr.js"></script>
60.17 <script src="/vm.js"></script>
60.18 <script type="text/javascript">
60.19 - vm.loadClass('${package}.Index');
60.20 + vm.loadClass('${package}.App');
60.21 </script>
60.22 </body>
60.23 </html>
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
61.2 +++ b/mojo/src/main/resources/archetype-resources/src/test/java/AppTest.java Wed Jan 23 12:53:23 2013 +0100
61.3 @@ -0,0 +1,26 @@
61.4 +package ${package};
61.5 +
61.6 +import static org.testng.Assert.*;
61.7 +import org.testng.annotations.BeforeMethod;
61.8 +import org.testng.annotations.Test;
61.9 +
61.10 +/** Demonstrating POJO testing of HTML page model. Runs in good old HotSpot
61.11 + * as it does not reference any HTML elements or browser functionality. Just
61.12 + * operates on the page model.
61.13 + *
61.14 + * @author Jaroslav Tulach <jtulach@netbeans.org>
61.15 + */
61.16 +public class AppTest {
61.17 + private Index model;
61.18 +
61.19 +
61.20 + @BeforeMethod
61.21 + public void initModel() {
61.22 + model = new Index().applyBindings();
61.23 + }
61.24 +
61.25 + @Test public void testHelloMessage() {
61.26 + model.setName("Joe");
61.27 + assertEquals(model.getHelloMessage(), "Hello Joe!", "Cleared after pressing +");
61.28 + }
61.29 +}
62.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
62.2 +++ b/mojo/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java Wed Jan 23 12:53:23 2013 +0100
62.3 @@ -0,0 +1,40 @@
62.4 +package ${package};
62.5 +
62.6 +import org.apidesign.bck2brwsr.vmtest.Compare;
62.7 +import org.apidesign.bck2brwsr.vmtest.VMTest;
62.8 +import org.testng.annotations.Factory;
62.9 +
62.10 +/** Bck2brwsr cares about compatibility with real Java. Whatever API is
62.11 + * supported by bck2brwsr, it needs to behave the same way as when running
62.12 + * in HotSpot VM.
62.13 + * <p>
62.14 + * There can be bugs, however. To help us fix them, we kindly ask you to
62.15 + * write an "inconsistency" test. A test that compares behavior of the API
62.16 + * between real VM and bck2brwsr VM. This class is skeleton of such test.
62.17 + *
62.18 + * @author Jaroslav Tulach <jtulach@netbeans.org>
62.19 + */
62.20 +public class InconsistencyTest {
62.21 + /** A method to demonstrate inconsistency between bck2brwsr and HotSpot.
62.22 + * Make calls to an API that behaves strangely, return some result at
62.23 + * the end. No need to use any <code>assert</code>.
62.24 + *
62.25 + * @return value to compare between HotSpot and bck2brwsr
62.26 + */
62.27 + @Compare
62.28 + public int checkStringHashCode() throws Exception {
62.29 + return "Is string hashCode the same?".hashCode();
62.30 + }
62.31 +
62.32 + /** Factory method that creates a three tests for each method annotated with
62.33 + * {@link org.apidesign.bck2brwsr.vmtest.Compare}. One executes the code in
62.34 + * HotSpot, one in Rhino and the last one compares the results.
62.35 + *
62.36 + * @see org.apidesign.bck2brwsr.vmtest.VMTest
62.37 + */
62.38 + @Factory
62.39 + public static Object[] create() {
62.40 + return VMTest.create(InconsistencyTest.class);
62.41 + }
62.42 +
62.43 +}
63.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
63.2 +++ b/mojo/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java Wed Jan 23 12:53:23 2013 +0100
63.3 @@ -0,0 +1,46 @@
63.4 +package ${package};
63.5 +
63.6 +import org.apidesign.bck2brwsr.htmlpage.api.OnEvent;
63.7 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
63.8 +import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
63.9 +import org.apidesign.bck2brwsr.vmtest.VMTest;
63.10 +import org.testng.annotations.Factory;
63.11 +
63.12 +/** Sometimes it is useful to run tests inside of the real browser.
63.13 + * To do that just annotate your method with {@link org.apidesign.bck2brwsr.vmtest.BrwsrTest}
63.14 + * and that is it. If your code references elements on the HTML page,
63.15 + * you can pass in an {@link org.apidesign.bck2brwsr.vmtest.HtmlFragment} which
63.16 + * will be made available on the page before your test starts.
63.17 + *
63.18 + * @author Jaroslav Tulach <jtulach@netbeans.org>
63.19 + */
63.20 +public class IntegrationTest {
63.21 +
63.22 + /** Write to testing code here. Use <code>assert</code> (but not TestNG's
63.23 + * Assert, as TestNG is not compiled with target 1.6 yet).
63.24 + */
63.25 + @HtmlFragment(
63.26 + "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
63.27 + "Your name: <input id='input' data-bind=\"value: name, valueUpdate: 'afterkeydown'\"></input>\n" +
63.28 + "<button id=\"hello\">Say Hello!</button>\n" +
63.29 + "<p>\n" +
63.30 + " <canvas id=\"canvas\" width=\"300\" height=\"50\"></canvas>\n" +
63.31 + "</p>\n"
63.32 + )
63.33 + @BrwsrTest
63.34 + public void modifyValueAssertChangeInModel() {
63.35 + Index m = new Index();
63.36 + m.setName("Joe Hacker");
63.37 + m.applyBindings();
63.38 + assert "Joe Hacker".equals(m.INPUT.getValue()) : "Value is really Joe Hacker: " + m.INPUT.getValue();
63.39 + m.INPUT.setValue("Happy Joe");
63.40 + m.triggerEvent(m.INPUT, OnEvent.CHANGE);
63.41 + assert "Happy Joe".equals(m.getName()) : "Name property updated to Happy Joe: " + m.getName();
63.42 + }
63.43 +
63.44 + @Factory
63.45 + public static Object[] create() {
63.46 + return VMTest.create(IntegrationTest.class);
63.47 + }
63.48 +
63.49 +}
64.1 --- a/pom.xml Tue Jan 22 19:48:10 2013 +0100
64.2 +++ b/pom.xml Wed Jan 23 12:53:23 2013 +0100
64.3 @@ -76,6 +76,7 @@
64.4 <exclude>mojo/src/main/resources/archetype-resources/**</exclude>
64.5 <exclude>launcher/src/main/resources/org/apidesign/bck2brwsr/dew/**</exclude>
64.6 <exclude>vmtest/src/test/resources/**</exclude>
64.7 + <exclude>javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout*.js</exclude>
64.8 </excludes>
64.9 </configuration>
64.10 </plugin>
65.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Jan 22 19:48:10 2013 +0100
65.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Jan 23 12:53:23 2013 +0100
65.3 @@ -52,7 +52,7 @@
65.4 /*
65.5 * @param resourcePath name of resources to read
65.6 */
65.7 - protected abstract void requireScript(String resourcePath);
65.8 + protected abstract void requireScript(String resourcePath) throws IOException;
65.9
65.10 /** Allows subclasses to redefine what field a function representing a
65.11 * class gets assigned. By default it returns the suggested name followed
65.12 @@ -212,7 +212,7 @@
65.13 out.append("\n return this;");
65.14 out.append("\n }");
65.15 out.append("\n return arguments[0] ? new CLS() : CLS.prototype;");
65.16 - out.append("\n}");
65.17 + out.append("\n};");
65.18 StringBuilder sb = new StringBuilder();
65.19 for (String init : toInitilize.toArray()) {
65.20 sb.append("\n").append(init).append("();");
65.21 @@ -264,37 +264,10 @@
65.22
65.23 final StackMapper smapper = new StackMapper();
65.24
65.25 - final int maxLocals = m.getMaxLocals();
65.26 - if (maxLocals > 0) {
65.27 - // TODO: generate only used local variables
65.28 - for (int j = 0; j <= VarType.LAST; ++j) {
65.29 - out.append("\n var ").append(Variable.getLocalVariable(j, 0));
65.30 - for (int i = 1; i < maxLocals; ++i) {
65.31 - out.append(", ");
65.32 - out.append(Variable.getLocalVariable(j, i));
65.33 - }
65.34 - out.append(';');
65.35 - }
65.36 - }
65.37 if (!m.isStatic()) {
65.38 out.append(" var ").append(" lcA0 = this;\n");
65.39 }
65.40
65.41 - // maxStack includes two stack positions for every pushed long / double
65.42 - // so this might generate more stack variables than we need
65.43 - final int maxStack = m.getMaxStack();
65.44 - if (maxStack > 0) {
65.45 - // TODO: generate only used stack variables
65.46 - for (int j = 0; j <= VarType.LAST; ++j) {
65.47 - out.append("\n var ").append(Variable.getStackVariable(j, 0));
65.48 - for (int i = 1; i < maxStack; ++i) {
65.49 - out.append(", ");
65.50 - out.append(Variable.getStackVariable(j, i));
65.51 - }
65.52 - out.append(';');
65.53 - }
65.54 - }
65.55 -
65.56 int lastStackFrame = -1;
65.57 TrapData[] previousTrap = null;
65.58
65.59 @@ -325,174 +298,184 @@
65.60 final int c = readByte(byteCodes, i);
65.61 switch (c) {
65.62 case opc_aload_0:
65.63 - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(0));
65.64 + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(0));
65.65 break;
65.66 case opc_iload_0:
65.67 - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(0));
65.68 + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(0));
65.69 break;
65.70 case opc_lload_0:
65.71 - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(0));
65.72 + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(0));
65.73 break;
65.74 case opc_fload_0:
65.75 - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(0));
65.76 + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(0));
65.77 break;
65.78 case opc_dload_0:
65.79 - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(0));
65.80 + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(0));
65.81 break;
65.82 case opc_aload_1:
65.83 - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(1));
65.84 + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(1));
65.85 break;
65.86 case opc_iload_1:
65.87 - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(1));
65.88 + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(1));
65.89 break;
65.90 case opc_lload_1:
65.91 - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(1));
65.92 + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(1));
65.93 break;
65.94 case opc_fload_1:
65.95 - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(1));
65.96 + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(1));
65.97 break;
65.98 case opc_dload_1:
65.99 - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(1));
65.100 + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(1));
65.101 break;
65.102 case opc_aload_2:
65.103 - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(2));
65.104 + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(2));
65.105 break;
65.106 case opc_iload_2:
65.107 - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(2));
65.108 + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(2));
65.109 break;
65.110 case opc_lload_2:
65.111 - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(2));
65.112 + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(2));
65.113 break;
65.114 case opc_fload_2:
65.115 - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(2));
65.116 + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(2));
65.117 break;
65.118 case opc_dload_2:
65.119 - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(2));
65.120 + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(2));
65.121 break;
65.122 case opc_aload_3:
65.123 - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(3));
65.124 + emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(3));
65.125 break;
65.126 case opc_iload_3:
65.127 - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(3));
65.128 + emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(3));
65.129 break;
65.130 case opc_lload_3:
65.131 - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(3));
65.132 + emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(3));
65.133 break;
65.134 case opc_fload_3:
65.135 - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(3));
65.136 + emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(3));
65.137 break;
65.138 case opc_dload_3:
65.139 - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(3));
65.140 + emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(3));
65.141 break;
65.142 case opc_iload: {
65.143 final int indx = readByte(byteCodes, ++i);
65.144 - emit(out, "@1 = @2;", smapper.pushI(), lmapper.getI(indx));
65.145 + emit(out, "var @1 = @2;",
65.146 + smapper.pushI(), lmapper.getI(indx));
65.147 break;
65.148 }
65.149 case opc_lload: {
65.150 final int indx = readByte(byteCodes, ++i);
65.151 - emit(out, "@1 = @2;", smapper.pushL(), lmapper.getL(indx));
65.152 + emit(out, "var @1 = @2;",
65.153 + smapper.pushL(), lmapper.getL(indx));
65.154 break;
65.155 }
65.156 case opc_fload: {
65.157 final int indx = readByte(byteCodes, ++i);
65.158 - emit(out, "@1 = @2;", smapper.pushF(), lmapper.getF(indx));
65.159 + emit(out, "var @1 = @2;",
65.160 + smapper.pushF(), lmapper.getF(indx));
65.161 break;
65.162 }
65.163 case opc_dload: {
65.164 final int indx = readByte(byteCodes, ++i);
65.165 - emit(out, "@1 = @2;", smapper.pushD(), lmapper.getD(indx));
65.166 + emit(out, "var @1 = @2;",
65.167 + smapper.pushD(), lmapper.getD(indx));
65.168 break;
65.169 }
65.170 case opc_aload: {
65.171 final int indx = readByte(byteCodes, ++i);
65.172 - emit(out, "@1 = @2;", smapper.pushA(), lmapper.getA(indx));
65.173 + emit(out, "var @1 = @2;",
65.174 + smapper.pushA(), lmapper.getA(indx));
65.175 break;
65.176 }
65.177 case opc_istore: {
65.178 final int indx = readByte(byteCodes, ++i);
65.179 - emit(out, "@1 = @2;", lmapper.setI(indx), smapper.popI());
65.180 + emit(out, "var @1 = @2;",
65.181 + lmapper.setI(indx), smapper.popI());
65.182 break;
65.183 }
65.184 case opc_lstore: {
65.185 final int indx = readByte(byteCodes, ++i);
65.186 - emit(out, "@1 = @2;", lmapper.setL(indx), smapper.popL());
65.187 + emit(out, "var @1 = @2;",
65.188 + lmapper.setL(indx), smapper.popL());
65.189 break;
65.190 }
65.191 case opc_fstore: {
65.192 final int indx = readByte(byteCodes, ++i);
65.193 - emit(out, "@1 = @2;", lmapper.setF(indx), smapper.popF());
65.194 + emit(out, "var @1 = @2;",
65.195 + lmapper.setF(indx), smapper.popF());
65.196 break;
65.197 }
65.198 case opc_dstore: {
65.199 final int indx = readByte(byteCodes, ++i);
65.200 - emit(out, "@1 = @2;", lmapper.setD(indx), smapper.popD());
65.201 + emit(out, "var @1 = @2;",
65.202 + lmapper.setD(indx), smapper.popD());
65.203 break;
65.204 }
65.205 case opc_astore: {
65.206 final int indx = readByte(byteCodes, ++i);
65.207 - emit(out, "@1 = @2;", lmapper.setA(indx), smapper.popA());
65.208 + emit(out, "var @1 = @2;",
65.209 + lmapper.setA(indx), smapper.popA());
65.210 break;
65.211 }
65.212 case opc_astore_0:
65.213 - emit(out, "@1 = @2;", lmapper.setA(0), smapper.popA());
65.214 + emit(out, "var @1 = @2;", lmapper.setA(0), smapper.popA());
65.215 break;
65.216 case opc_istore_0:
65.217 - emit(out, "@1 = @2;", lmapper.setI(0), smapper.popI());
65.218 + emit(out, "var @1 = @2;", lmapper.setI(0), smapper.popI());
65.219 break;
65.220 case opc_lstore_0:
65.221 - emit(out, "@1 = @2;", lmapper.setL(0), smapper.popL());
65.222 + emit(out, "var @1 = @2;", lmapper.setL(0), smapper.popL());
65.223 break;
65.224 case opc_fstore_0:
65.225 - emit(out, "@1 = @2;", lmapper.setF(0), smapper.popF());
65.226 + emit(out, "var @1 = @2;", lmapper.setF(0), smapper.popF());
65.227 break;
65.228 case opc_dstore_0:
65.229 - emit(out, "@1 = @2;", lmapper.setD(0), smapper.popD());
65.230 + emit(out, "var @1 = @2;", lmapper.setD(0), smapper.popD());
65.231 break;
65.232 case opc_astore_1:
65.233 - emit(out, "@1 = @2;", lmapper.setA(1), smapper.popA());
65.234 + emit(out, "var @1 = @2;", lmapper.setA(1), smapper.popA());
65.235 break;
65.236 case opc_istore_1:
65.237 - emit(out, "@1 = @2;", lmapper.setI(1), smapper.popI());
65.238 + emit(out, "var @1 = @2;", lmapper.setI(1), smapper.popI());
65.239 break;
65.240 case opc_lstore_1:
65.241 - emit(out, "@1 = @2;", lmapper.setL(1), smapper.popL());
65.242 + emit(out, "var @1 = @2;", lmapper.setL(1), smapper.popL());
65.243 break;
65.244 case opc_fstore_1:
65.245 - emit(out, "@1 = @2;", lmapper.setF(1), smapper.popF());
65.246 + emit(out, "var @1 = @2;", lmapper.setF(1), smapper.popF());
65.247 break;
65.248 case opc_dstore_1:
65.249 - emit(out, "@1 = @2;", lmapper.setD(1), smapper.popD());
65.250 + emit(out, "var @1 = @2;", lmapper.setD(1), smapper.popD());
65.251 break;
65.252 case opc_astore_2:
65.253 - emit(out, "@1 = @2;", lmapper.setA(2), smapper.popA());
65.254 + emit(out, "var @1 = @2;", lmapper.setA(2), smapper.popA());
65.255 break;
65.256 case opc_istore_2:
65.257 - emit(out, "@1 = @2;", lmapper.setI(2), smapper.popI());
65.258 + emit(out, "var @1 = @2;", lmapper.setI(2), smapper.popI());
65.259 break;
65.260 case opc_lstore_2:
65.261 - emit(out, "@1 = @2;", lmapper.setL(2), smapper.popL());
65.262 + emit(out, "var @1 = @2;", lmapper.setL(2), smapper.popL());
65.263 break;
65.264 case opc_fstore_2:
65.265 - emit(out, "@1 = @2;", lmapper.setF(2), smapper.popF());
65.266 + emit(out, "var @1 = @2;", lmapper.setF(2), smapper.popF());
65.267 break;
65.268 case opc_dstore_2:
65.269 - emit(out, "@1 = @2;", lmapper.setD(2), smapper.popD());
65.270 + emit(out, "var @1 = @2;", lmapper.setD(2), smapper.popD());
65.271 break;
65.272 case opc_astore_3:
65.273 - emit(out, "@1 = @2;", lmapper.setA(3), smapper.popA());
65.274 + emit(out, "var @1 = @2;", lmapper.setA(3), smapper.popA());
65.275 break;
65.276 case opc_istore_3:
65.277 - emit(out, "@1 = @2;", lmapper.setI(3), smapper.popI());
65.278 + emit(out, "var @1 = @2;", lmapper.setI(3), smapper.popI());
65.279 break;
65.280 case opc_lstore_3:
65.281 - emit(out, "@1 = @2;", lmapper.setL(3), smapper.popL());
65.282 + emit(out, "var @1 = @2;", lmapper.setL(3), smapper.popL());
65.283 break;
65.284 case opc_fstore_3:
65.285 - emit(out, "@1 = @2;", lmapper.setF(3), smapper.popF());
65.286 + emit(out, "var @1 = @2;", lmapper.setF(3), smapper.popF());
65.287 break;
65.288 case opc_dstore_3:
65.289 - emit(out, "@1 = @2;", lmapper.setD(3), smapper.popD());
65.290 + emit(out, "var @1 = @2;", lmapper.setD(3), smapper.popD());
65.291 break;
65.292 case opc_iadd:
65.293 emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI());
65.294 @@ -635,105 +618,105 @@
65.295 emit(out, "return @1;", smapper.popA());
65.296 break;
65.297 case opc_i2l:
65.298 - emit(out, "@2 = @1;", smapper.popI(), smapper.pushL());
65.299 + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushL());
65.300 break;
65.301 case opc_i2f:
65.302 - emit(out, "@2 = @1;", smapper.popI(), smapper.pushF());
65.303 + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushF());
65.304 break;
65.305 case opc_i2d:
65.306 - emit(out, "@2 = @1;", smapper.popI(), smapper.pushD());
65.307 + emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD());
65.308 break;
65.309 case opc_l2i:
65.310 - emit(out, "@2 = @1;", smapper.popL(), smapper.pushI());
65.311 + emit(out, "var @2 = @1;", smapper.popL(), smapper.pushI());
65.312 break;
65.313 // max int check?
65.314 case opc_l2f:
65.315 - emit(out, "@2 = @1;", smapper.popL(), smapper.pushF());
65.316 + emit(out, "var @2 = @1;", smapper.popL(), smapper.pushF());
65.317 break;
65.318 case opc_l2d:
65.319 - emit(out, "@2 = @1;", smapper.popL(), smapper.pushD());
65.320 + emit(out, "var @2 = @1;", smapper.popL(), smapper.pushD());
65.321 break;
65.322 case opc_f2d:
65.323 - emit(out, "@2 = @1;", smapper.popF(), smapper.pushD());
65.324 + emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD());
65.325 break;
65.326 case opc_d2f:
65.327 - emit(out, "@2 = @1;", smapper.popD(), smapper.pushF());
65.328 + emit(out, "var @2 = @1;", smapper.popD(), smapper.pushF());
65.329 break;
65.330 case opc_f2i:
65.331 - emit(out, "@2 = Math.floor(@1);",
65.332 + emit(out, "var @2 = Math.floor(@1);",
65.333 smapper.popF(), smapper.pushI());
65.334 break;
65.335 case opc_f2l:
65.336 - emit(out, "@2 = Math.floor(@1);",
65.337 + emit(out, "var @2 = Math.floor(@1);",
65.338 smapper.popF(), smapper.pushL());
65.339 break;
65.340 case opc_d2i:
65.341 - emit(out, "@2 = Math.floor(@1);",
65.342 + emit(out, "var @2 = Math.floor(@1);",
65.343 smapper.popD(), smapper.pushI());
65.344 break;
65.345 case opc_d2l:
65.346 - emit(out, "@2 = Math.floor(@1);",
65.347 + emit(out, "var @2 = Math.floor(@1);",
65.348 smapper.popD(), smapper.pushL());
65.349 break;
65.350 case opc_i2b:
65.351 - emit(out, "@1 = @1.toInt8();", smapper.getI(0));
65.352 + emit(out, "var @1 = @1.toInt8();", smapper.getI(0));
65.353 break;
65.354 case opc_i2c:
65.355 out.append("{ /* number conversion */ }");
65.356 break;
65.357 case opc_i2s:
65.358 - emit(out, "@1 = @1.toInt16();", smapper.getI(0));
65.359 + emit(out, "var @1 = @1.toInt16();", smapper.getI(0));
65.360 break;
65.361 case opc_aconst_null:
65.362 - emit(out, "@1 = null;", smapper.pushA());
65.363 + emit(out, "var @1 = null;", smapper.pushA());
65.364 break;
65.365 case opc_iconst_m1:
65.366 - emit(out, "@1 = -1;", smapper.pushI());
65.367 + emit(out, "var @1 = -1;", smapper.pushI());
65.368 break;
65.369 case opc_iconst_0:
65.370 - emit(out, "@1 = 0;", smapper.pushI());
65.371 + emit(out, "var @1 = 0;", smapper.pushI());
65.372 break;
65.373 case opc_dconst_0:
65.374 - emit(out, "@1 = 0;", smapper.pushD());
65.375 + emit(out, "var @1 = 0;", smapper.pushD());
65.376 break;
65.377 case opc_lconst_0:
65.378 - emit(out, "@1 = 0;", smapper.pushL());
65.379 + emit(out, "var @1 = 0;", smapper.pushL());
65.380 break;
65.381 case opc_fconst_0:
65.382 - emit(out, "@1 = 0;", smapper.pushF());
65.383 + emit(out, "var @1 = 0;", smapper.pushF());
65.384 break;
65.385 case opc_iconst_1:
65.386 - emit(out, "@1 = 1;", smapper.pushI());
65.387 + emit(out, "var @1 = 1;", smapper.pushI());
65.388 break;
65.389 case opc_lconst_1:
65.390 - emit(out, "@1 = 1;", smapper.pushL());
65.391 + emit(out, "var @1 = 1;", smapper.pushL());
65.392 break;
65.393 case opc_fconst_1:
65.394 - emit(out, "@1 = 1;", smapper.pushF());
65.395 + emit(out, "var @1 = 1;", smapper.pushF());
65.396 break;
65.397 case opc_dconst_1:
65.398 - emit(out, "@1 = 1;", smapper.pushD());
65.399 + emit(out, "var @1 = 1;", smapper.pushD());
65.400 break;
65.401 case opc_iconst_2:
65.402 - emit(out, "@1 = 2;", smapper.pushI());
65.403 + emit(out, "var @1 = 2;", smapper.pushI());
65.404 break;
65.405 case opc_fconst_2:
65.406 - emit(out, "@1 = 2;", smapper.pushF());
65.407 + emit(out, "var @1 = 2;", smapper.pushF());
65.408 break;
65.409 case opc_iconst_3:
65.410 - emit(out, "@1 = 3;", smapper.pushI());
65.411 + emit(out, "var @1 = 3;", smapper.pushI());
65.412 break;
65.413 case opc_iconst_4:
65.414 - emit(out, "@1 = 4;", smapper.pushI());
65.415 + emit(out, "var @1 = 4;", smapper.pushI());
65.416 break;
65.417 case opc_iconst_5:
65.418 - emit(out, "@1 = 5;", smapper.pushI());
65.419 + emit(out, "var @1 = 5;", smapper.pushI());
65.420 break;
65.421 case opc_ldc: {
65.422 int indx = readByte(byteCodes, ++i);
65.423 String v = encodeConstant(indx);
65.424 int type = VarType.fromConstantType(jc.getTag(indx));
65.425 - emit(out, "@1 = @2;", smapper.pushT(type), v);
65.426 + emit(out, "var @1 = @2;", smapper.pushT(type), v);
65.427 break;
65.428 }
65.429 case opc_ldc_w:
65.430 @@ -742,21 +725,21 @@
65.431 i += 2;
65.432 String v = encodeConstant(indx);
65.433 int type = VarType.fromConstantType(jc.getTag(indx));
65.434 - emit(out, "@1 = @2;", smapper.pushT(type), v);
65.435 + emit(out, "var @1 = @2;", smapper.pushT(type), v);
65.436 break;
65.437 }
65.438 case opc_lcmp:
65.439 - emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
65.440 + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
65.441 smapper.popL(), smapper.popL(), smapper.pushI());
65.442 break;
65.443 case opc_fcmpl:
65.444 case opc_fcmpg:
65.445 - emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
65.446 + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
65.447 smapper.popF(), smapper.popF(), smapper.pushI());
65.448 break;
65.449 case opc_dcmpl:
65.450 case opc_dcmpg:
65.451 - emit(out, "@3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
65.452 + emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
65.453 smapper.popD(), smapper.popD(), smapper.pushI());
65.454 break;
65.455 case opc_if_acmpeq:
65.456 @@ -906,7 +889,7 @@
65.457 case opc_new: {
65.458 int indx = readIntArg(byteCodes, i);
65.459 String ci = jc.getClassName(indx);
65.460 - emit(out, "@1 = new @2;",
65.461 + emit(out, "var @1 = new @2;",
65.462 smapper.pushA(), accessClass(ci.replace('/', '_')));
65.463 addReference(ci);
65.464 i += 2;
65.465 @@ -926,7 +909,7 @@
65.466 case 11: jvmType = "[J"; break;
65.467 default: throw new IllegalStateException("Array type: " + atype);
65.468 }
65.469 - emit(out, "@2 = new Array(@1).initWith('@3', 0);",
65.470 + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
65.471 smapper.popI(), smapper.pushA(), jvmType);
65.472 break;
65.473 case opc_anewarray: {
65.474 @@ -938,7 +921,7 @@
65.475 } else {
65.476 typeName = "[L" + typeName + ";";
65.477 }
65.478 - emit(out, "@2 = new Array(@1).initWith('@3', null);",
65.479 + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
65.480 smapper.popI(), smapper.pushA(), typeName);
65.481 break;
65.482 }
65.483 @@ -947,30 +930,22 @@
65.484 i += 2;
65.485 String typeName = jc.getClassName(type);
65.486 int dim = readByte(byteCodes, ++i);
65.487 - out.append("{ var a0 = new Array(").append(smapper.popI())
65.488 - .append(").initWith('").append(typeName).append("', null);");
65.489 - for (int d = 1; d < dim; d++) {
65.490 - typeName = typeName.substring(1);
65.491 - out.append("\n var l" + d).append(" = ")
65.492 - .append(smapper.popI()).append(';');
65.493 - out.append("\n for (var i" + d).append (" = 0; i" + d).
65.494 - append(" < a" + (d - 1)).
65.495 - append(".length; i" + d).append("++) {");
65.496 - out.append("\n var a" + d).
65.497 - append (" = new Array(l" + d).append(").initWith('")
65.498 - .append(typeName).append("', ")
65.499 - .append(typeName.length() == 2 ? "0" : "null").append(");");
65.500 - out.append("\n a" + (d - 1)).append("[i" + d).append("] = a" + d).
65.501 - append(";");
65.502 + StringBuilder dims = new StringBuilder();
65.503 + dims.append('[');
65.504 + for (int d = 0; d < dim; d++) {
65.505 + if (d != 0) {
65.506 + dims.append(",");
65.507 + }
65.508 + dims.append(smapper.popI());
65.509 }
65.510 - for (int d = 1; d < dim; d++) {
65.511 - out.append("\n }");
65.512 - }
65.513 - out.append("\n").append(smapper.pushA()).append(" = a0; }");
65.514 + dims.append(']');
65.515 + emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
65.516 + dims.toString(), smapper.pushA(), typeName);
65.517 break;
65.518 }
65.519 case opc_arraylength:
65.520 - emit(out, "@2 = @1.length;", smapper.popA(), smapper.pushI());
65.521 + emit(out, "var @2 = @1.length;",
65.522 + smapper.popA(), smapper.pushI());
65.523 break;
65.524 case opc_lastore:
65.525 emit(out, "@3.at(@2, @1);",
65.526 @@ -996,26 +971,26 @@
65.527 smapper.popI(), smapper.popI(), smapper.popA());
65.528 break;
65.529 case opc_laload:
65.530 - emit(out, "@3 = @2.at(@1);",
65.531 + emit(out, "var @3 = @2.at(@1);",
65.532 smapper.popI(), smapper.popA(), smapper.pushL());
65.533 break;
65.534 case opc_faload:
65.535 - emit(out, "@3 = @2.at(@1);",
65.536 + emit(out, "var @3 = @2.at(@1);",
65.537 smapper.popI(), smapper.popA(), smapper.pushF());
65.538 break;
65.539 case opc_daload:
65.540 - emit(out, "@3 = @2.at(@1);",
65.541 + emit(out, "var @3 = @2.at(@1);",
65.542 smapper.popI(), smapper.popA(), smapper.pushD());
65.543 break;
65.544 case opc_aaload:
65.545 - emit(out, "@3 = @2.at(@1);",
65.546 + emit(out, "var @3 = @2.at(@1);",
65.547 smapper.popI(), smapper.popA(), smapper.pushA());
65.548 break;
65.549 case opc_iaload:
65.550 case opc_baload:
65.551 case opc_caload:
65.552 case opc_saload:
65.553 - emit(out, "@3 = @2.at(@1);",
65.554 + emit(out, "var @3 = @2.at(@1);",
65.555 smapper.popI(), smapper.popA(), smapper.pushI());
65.556 break;
65.557 case opc_pop:
65.558 @@ -1025,17 +1000,18 @@
65.559 break;
65.560 case opc_dup: {
65.561 final Variable v = smapper.get(0);
65.562 - emit(out, "@1 = @2;", smapper.pushT(v.getType()), v);
65.563 + emit(out, "var @1 = @2;", smapper.pushT(v.getType()), v);
65.564 break;
65.565 }
65.566 case opc_dup2: {
65.567 if (smapper.get(0).isCategory2()) {
65.568 final Variable v = smapper.get(0);
65.569 - emit(out, "@1 = @2;", smapper.pushT(v.getType()), v);
65.570 + emit(out, "var @1 = @2;",
65.571 + smapper.pushT(v.getType()), v);
65.572 } else {
65.573 final Variable v1 = smapper.get(0);
65.574 final Variable v2 = smapper.get(1);
65.575 - emit(out, "{ @1 = @2; @3 = @4; }",
65.576 + emit(out, "var @1 = @2, @3 = @4;",
65.577 smapper.pushT(v2.getType()), v2,
65.578 smapper.pushT(v1.getType()), v1);
65.579 }
65.580 @@ -1048,7 +1024,7 @@
65.581 final Variable vo2 = smapper.pushT(vi2.getType());
65.582 final Variable vo1 = smapper.pushT(vi1.getType());
65.583
65.584 - emit(out, "{ @1 = @2; @3 = @4; @5 = @6; }",
65.585 + emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
65.586 vo1, vi1, vo2, vi2, vo3, vo1);
65.587 break;
65.588 }
65.589 @@ -1060,7 +1036,7 @@
65.590 final Variable vo2 = smapper.pushT(vi2.getType());
65.591 final Variable vo1 = smapper.pushT(vi1.getType());
65.592
65.593 - emit(out, "{ @1 = @2; @3 = @4; @5 = @6; }",
65.594 + emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
65.595 vo1, vi1, vo2, vi2, vo3, vo1);
65.596 } else {
65.597 final Variable vi1 = smapper.pop();
65.598 @@ -1071,17 +1047,17 @@
65.599 final Variable vo2 = smapper.pushT(vi2.getType());
65.600 final Variable vo1 = smapper.pushT(vi1.getType());
65.601
65.602 - emit(out, "{ @1 = @2; @3 = @4; @5 = @6; @7 = @8; }",
65.603 + emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
65.604 vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
65.605 }
65.606 break;
65.607 }
65.608 case opc_bipush:
65.609 - emit(out, "@1 = @2;",
65.610 + emit(out, "var @1 = @2;",
65.611 smapper.pushI(), Integer.toString(byteCodes[++i]));
65.612 break;
65.613 case opc_sipush:
65.614 - emit(out, "@1 = @2;",
65.615 + emit(out, "var @1 = @2;",
65.616 smapper.pushI(),
65.617 Integer.toString(readIntArg(byteCodes, i)));
65.618 i += 2;
65.619 @@ -1090,7 +1066,7 @@
65.620 int indx = readIntArg(byteCodes, i);
65.621 String[] fi = jc.getFieldInfoName(indx);
65.622 final int type = VarType.fromFieldType(fi[2].charAt(0));
65.623 - emit(out, "@2 = @1.fld_@3;",
65.624 + emit(out, "var @2 = @1.fld_@3;",
65.625 smapper.popA(), smapper.pushT(type), fi[1]);
65.626 i += 2;
65.627 break;
65.628 @@ -1099,7 +1075,7 @@
65.629 int indx = readIntArg(byteCodes, i);
65.630 String[] fi = jc.getFieldInfoName(indx);
65.631 final int type = VarType.fromFieldType(fi[2].charAt(0));
65.632 - emit(out, "@1 = @2(false).constructor.@3;",
65.633 + emit(out, "var @1 = @2(false).constructor.@3;",
65.634 smapper.pushT(type),
65.635 accessClass(fi[0].replace('/', '_')), fi[1]);
65.636 i += 2;
65.637 @@ -1142,7 +1118,7 @@
65.638 case opc_instanceof: {
65.639 int indx = readIntArg(byteCodes, i);
65.640 final String type = jc.getClassName(indx);
65.641 - emit(out, "@2 = @1.$instOf_@3 ? 1 : 0;",
65.642 + emit(out, "var @2 = @1.$instOf_@3 ? 1 : 0;",
65.643 smapper.popA(), smapper.pushI(),
65.644 type.replace('/', '_'));
65.645 i += 2;
65.646 @@ -1152,7 +1128,7 @@
65.647 final Variable v = smapper.popA();
65.648 smapper.clear();
65.649
65.650 - emit(out, "{ @1 = @2; throw @2; }",
65.651 + emit(out, "{ var @1 = @2; throw @2; }",
65.652 smapper.pushA(), v);
65.653 break;
65.654 }
65.655 @@ -1352,7 +1328,8 @@
65.656 }
65.657
65.658 if (returnType[0] != 'V') {
65.659 - out.append(mapper.pushT(VarType.fromFieldType(returnType[0])))
65.660 + out.append("var ")
65.661 + .append(mapper.pushT(VarType.fromFieldType(returnType[0])))
65.662 .append(" = ");
65.663 }
65.664
65.665 @@ -1396,7 +1373,8 @@
65.666 }
65.667
65.668 if (returnType[0] != 'V') {
65.669 - out.append(mapper.pushT(VarType.fromFieldType(returnType[0])))
65.670 + out.append("var ")
65.671 + .append(mapper.pushT(VarType.fromFieldType(returnType[0])))
65.672 .append(" = ");
65.673 }
65.674
65.675 @@ -1628,15 +1606,15 @@
65.676 addReference(classInternalName);
65.677 if ("java/lang/Throwable".equals(classInternalName)) {
65.678 out.append("if (e.$instOf_java_lang_Throwable) {");
65.679 - out.append(" stA0 = e;");
65.680 + out.append(" var stA0 = e;");
65.681 out.append("} else {");
65.682 - out.append(" stA0 = vm.java_lang_Throwable(true);");
65.683 + out.append(" var stA0 = vm.java_lang_Throwable(true);");
65.684 out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());");
65.685 out.append("}");
65.686 out.append("gt=" + e.handler_pc + "; continue;");
65.687 } else {
65.688 out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {");
65.689 - out.append("gt=" + e.handler_pc + "; stA0 = e; continue;");
65.690 + out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;");
65.691 out.append("}\n");
65.692 }
65.693 } else {
65.694 @@ -1646,7 +1624,7 @@
65.695 if (finallyPC == -1) {
65.696 out.append("throw e;");
65.697 } else {
65.698 - out.append("gt=" + finallyPC + "; stA0 = e; continue;");
65.699 + out.append("gt=" + finallyPC + "; var stA0 = e; continue;");
65.700 }
65.701 out.append("\n}");
65.702 }
66.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Tue Jan 22 19:48:10 2013 +0100
66.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Wed Jan 23 12:53:23 2013 +0100
66.3 @@ -19,6 +19,7 @@
66.4
66.5 import java.io.ByteArrayInputStream;
66.6 import java.io.IOException;
66.7 +import java.io.InputStream;
66.8 import org.apidesign.bck2brwsr.core.JavaScriptBody;
66.9
66.10 /**
66.11 @@ -131,7 +132,17 @@
66.12 }
66.13
66.14 @Override
66.15 - protected void requireScript(String resourcePath) {
66.16 + protected void requireScript(String resourcePath) throws IOException {
66.17 + InputStream is = getClass().getResourceAsStream(resourcePath);
66.18 + StringBuilder sb = new StringBuilder();
66.19 + for (;;) {
66.20 + int ch = is.read();
66.21 + if (ch == -1) {
66.22 + break;
66.23 + }
66.24 + sb.append((char)ch);
66.25 + }
66.26 + applyCode(lazy.loader, null, sb.toString(), false);
66.27 }
66.28
66.29 @Override
67.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
67.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Script.java Wed Jan 23 12:53:23 2013 +0100
67.3 @@ -0,0 +1,31 @@
67.4 +/**
67.5 + * Back 2 Browser Bytecode Translator
67.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
67.7 + *
67.8 + * This program is free software: you can redistribute it and/or modify
67.9 + * it under the terms of the GNU General Public License as published by
67.10 + * the Free Software Foundation, version 2 of the License.
67.11 + *
67.12 + * This program is distributed in the hope that it will be useful,
67.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
67.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
67.15 + * GNU General Public License for more details.
67.16 + *
67.17 + * You should have received a copy of the GNU General Public License
67.18 + * along with this program. Look for COPYING file in the top folder.
67.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
67.20 + */
67.21 +package org.apidesign.vm4brwsr;
67.22 +
67.23 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
67.24 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
67.25 +
67.26 +/** Test to verify external scripts are processed in lazy mode.
67.27 + *
67.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
67.29 + */
67.30 +@ExtraJavaScript(resource = "/org/apidesign/vm4brwsr/ko.js")
67.31 +public class Script {
67.32 + @JavaScriptBody(args = { }, body = "return ko !== null;")
67.33 + public static native boolean checkNotNull();
67.34 +}
68.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Tue Jan 22 19:48:10 2013 +0100
68.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Wed Jan 23 12:53:23 2013 +0100
68.3 @@ -45,7 +45,9 @@
68.4 sb.append("\n return c[method]();");
68.5 sb.append("\n}");
68.6
68.7 -
68.8 + sb.append("\nfunction checkKO() {");
68.9 + sb.append("\n return ko !== null;");
68.10 + sb.append("\n}");
68.11
68.12 ScriptEngine[] arr = { null };
68.13 code = StaticMethodTest.compileClass(sb, arr,
68.14 @@ -67,6 +69,15 @@
68.15 );
68.16 }
68.17
68.18 + @Test public void loadClassWithAssociatedScript() throws Exception {
68.19 + assertExec("ko is defined", "test", true,
68.20 + Script.class.getName(), "checkNotNull__Z"
68.21 + );
68.22 +
68.23 + Object res = code.invokeFunction("checkKO");
68.24 + assertEquals(res, true, "KO is defined on a global level");
68.25 + }
68.26 +
68.27 private static void assertExec(String msg, String methodName, Object expRes, Object... args) throws Exception {
68.28 Object ret = null;
68.29 try {
69.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
69.2 +++ b/vm/src/test/resources/org/apidesign/vm4brwsr/ko.js Wed Jan 23 12:53:23 2013 +0100
69.3 @@ -0,0 +1,20 @@
69.4 +/*
69.5 + * Back 2 Browser Bytecode Translator
69.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
69.7 + *
69.8 + * This program is free software: you can redistribute it and/or modify
69.9 + * it under the terms of the GNU General Public License as published by
69.10 + * the Free Software Foundation, version 2 of the License.
69.11 + *
69.12 + * This program is distributed in the hope that it will be useful,
69.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
69.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
69.15 + * GNU General Public License for more details.
69.16 + *
69.17 + * You should have received a copy of the GNU General Public License
69.18 + * along with this program. Look for COPYING file in the top folder.
69.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
69.20 + */
69.21 +this.ko = {};
69.22 +
69.23 +
70.1 --- a/vmtest/pom.xml Tue Jan 22 19:48:10 2013 +0100
70.2 +++ b/vmtest/pom.xml Wed Jan 23 12:53:23 2013 +0100
70.3 @@ -44,13 +44,14 @@
70.4 <dependency>
70.5 <groupId>${project.groupId}</groupId>
70.6 <artifactId>vm4brwsr</artifactId>
70.7 - <version>0.3-SNAPSHOT</version>
70.8 + <version>${project.version}</version>
70.9 <type>jar</type>
70.10 </dependency>
70.11 <dependency>
70.12 <groupId>${project.groupId}</groupId>
70.13 <artifactId>emul</artifactId>
70.14 - <version>0.3-SNAPSHOT</version>
70.15 + <version>${project.version}</version>
70.16 + <scope>test</scope>
70.17 </dependency>
70.18 <dependency>
70.19 <groupId>${project.groupId}</groupId>
71.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
71.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/BrwsrTest.java Wed Jan 23 12:53:23 2013 +0100
71.3 @@ -0,0 +1,38 @@
71.4 +/**
71.5 + * Back 2 Browser Bytecode Translator
71.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
71.7 + *
71.8 + * This program is free software: you can redistribute it and/or modify
71.9 + * it under the terms of the GNU General Public License as published by
71.10 + * the Free Software Foundation, version 2 of the License.
71.11 + *
71.12 + * This program is distributed in the hope that it will be useful,
71.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
71.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
71.15 + * GNU General Public License for more details.
71.16 + *
71.17 + * You should have received a copy of the GNU General Public License
71.18 + * along with this program. Look for COPYING file in the top folder.
71.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
71.20 + */
71.21 +package org.apidesign.bck2brwsr.vmtest;
71.22 +
71.23 +import java.lang.annotation.ElementType;
71.24 +import java.lang.annotation.Retention;
71.25 +import java.lang.annotation.RetentionPolicy;
71.26 +import java.lang.annotation.Target;
71.27 +
71.28 +/** Annotation to indicate that given method should be executed
71.29 + * in a browser environment. Has to be used in conjunction with {@link VMTest#create(java.lang.Class)}
71.30 + * factory method.
71.31 + * <p>
71.32 + * The browser to is by default executed via {@link java.awt.Desktop#browse(java.net.URI)},
71.33 + * but one can change that by specifying <code>-Dvmtest.brwsrs=firefox,google-chrome</code>
71.34 + * property.
71.35 + *
71.36 + * @author Jaroslav Tulach <jtulach@netbeans.org>
71.37 + */
71.38 +@Retention(RetentionPolicy.RUNTIME)
71.39 +@Target(ElementType.METHOD)
71.40 +public @interface BrwsrTest {
71.41 +}
72.1 --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Compare.java Tue Jan 22 19:48:10 2013 +0100
72.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Compare.java Wed Jan 23 12:53:23 2013 +0100
72.3 @@ -24,7 +24,7 @@
72.4
72.5 /** Can be applied on a method that yields a return value.
72.6 * Together with {@link VMTest#create} it can be used to write
72.7 - * methods which are executed in real as well as JavaScript VMs and
72.8 + * methods which are executed in real VM as well as JavaScript VMs and
72.9 * their results are compared.
72.10 *
72.11 * @author Jaroslav Tulach <jtulach@netbeans.org>
72.12 @@ -32,5 +32,14 @@
72.13 @Retention(RetentionPolicy.RUNTIME)
72.14 @Target(ElementType.METHOD)
72.15 public @interface Compare {
72.16 -
72.17 + /** Specifies whether the system should internal JavaScript interpreter
72.18 + * as available via {@link javax.script.ScriptEngine}. Defaults to true,
72.19 + * but in some situations (benchmarking comes to my mind), one may set this
72.20 + * to <code>false</code>. In such case only browsers provided via
72.21 + * <code>vmtest.brwsrs</code> property are used. For example
72.22 + * <code>"vmtest.brwsrs=firefox,google-chrome"</code> would run the test
72.23 + * in HotSpot VM, firefox and chrome and would compare the results.
72.24 + * @return
72.25 + */
72.26 + boolean scripting() default true;
72.27 }
73.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
73.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/HtmlFragment.java Wed Jan 23 12:53:23 2013 +0100
73.3 @@ -0,0 +1,38 @@
73.4 +/**
73.5 + * Back 2 Browser Bytecode Translator
73.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
73.7 + *
73.8 + * This program is free software: you can redistribute it and/or modify
73.9 + * it under the terms of the GNU General Public License as published by
73.10 + * the Free Software Foundation, version 2 of the License.
73.11 + *
73.12 + * This program is distributed in the hope that it will be useful,
73.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
73.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
73.15 + * GNU General Public License for more details.
73.16 + *
73.17 + * You should have received a copy of the GNU General Public License
73.18 + * along with this program. Look for COPYING file in the top folder.
73.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
73.20 + */
73.21 +package org.apidesign.bck2brwsr.vmtest;
73.22 +
73.23 +import java.lang.annotation.ElementType;
73.24 +import java.lang.annotation.Retention;
73.25 +import java.lang.annotation.RetentionPolicy;
73.26 +import java.lang.annotation.Target;
73.27 +
73.28 +/** Allows to specify an HTML fragment for a given {@link BrwsrTest}.
73.29 + * Apply either to the method or to enclosing class. The fragment will be
73.30 + * made available in the page that executes given test. Its elements shall
73.31 + * be regularly accessible from the test.
73.32 + *
73.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
73.34 + */
73.35 +@Retention(RetentionPolicy.RUNTIME)
73.36 +@Target({ ElementType.METHOD, ElementType.TYPE})
73.37 +public @interface HtmlFragment {
73.38 + /** HTML code fragment to be exposed on the testing page.
73.39 + */
73.40 + String value();
73.41 +}
74.1 --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Tue Jan 22 19:48:10 2013 +0100
74.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/Bck2BrwsrCase.java Wed Jan 23 12:53:23 2013 +0100
74.3 @@ -20,6 +20,7 @@
74.4 import java.io.File;
74.5 import java.io.FileWriter;
74.6 import java.io.IOException;
74.7 +import java.lang.reflect.Constructor;
74.8 import java.lang.reflect.InvocationTargetException;
74.9 import java.lang.reflect.Method;
74.10 import java.util.Map;
74.11 @@ -37,21 +38,56 @@
74.12 private final Method m;
74.13 private final Launcher l;
74.14 private final String type;
74.15 + private final boolean fail;
74.16 Object value;
74.17 - private static final Map<Class, Object[]> compiled = new WeakHashMap<>();
74.18 - private Object inst;
74.19 + private final String html;
74.20
74.21 - Bck2BrwsrCase(Method m, String type, Launcher l) {
74.22 + Bck2BrwsrCase(Method m, String type, Launcher l, boolean fail, String html) {
74.23 this.l = l;
74.24 this.m = m;
74.25 this.type = type;
74.26 + this.fail = fail;
74.27 + this.html = html;
74.28 }
74.29
74.30 @Test(groups = "run")
74.31 public void executeCode() throws Throwable {
74.32 if (l != null) {
74.33 - MethodInvocation c = l.invokeMethod(m.getDeclaringClass(), m.getName());
74.34 - value = c.toString();
74.35 + MethodInvocation c = l.invokeMethod(m.getDeclaringClass(), m.getName(), html);
74.36 + String res = c.toString();
74.37 + value = res;
74.38 + if (fail) {
74.39 + int idx = res.indexOf(':');
74.40 + if (idx >= 0) {
74.41 + Class<? extends Throwable> thrwbl = null;
74.42 + try {
74.43 + Class<?> exCls = Class.forName(res.substring(0, idx));
74.44 + if (Throwable.class.isAssignableFrom(exCls)) {
74.45 + thrwbl = exCls.asSubclass(Throwable.class);
74.46 + }
74.47 + } catch (Exception ex) {
74.48 + // ignore
74.49 + }
74.50 + if (thrwbl != null) {
74.51 + Throwable t = null;
74.52 + try {
74.53 + for (Constructor<?> cnstr : thrwbl.getConstructors()) {
74.54 + if (cnstr.getParameterTypes().length == 1 && cnstr.getParameterTypes()[0].isAssignableFrom(String.class)) {
74.55 + t = (Throwable) cnstr.newInstance(res.substring(idx + 1));
74.56 + break;
74.57 + }
74.58 + }
74.59 + } catch (Throwable ex) {
74.60 + t = thrwbl.newInstance().initCause(ex);
74.61 + }
74.62 + if (t == null) {
74.63 + t = thrwbl.newInstance().initCause(new Exception(res.substring(idx)));
74.64 + }
74.65 + throw t;
74.66 + }
74.67 + throw new AssertionError(res);
74.68 + }
74.69 + }
74.70 } else {
74.71 try {
74.72 value = m.invoke(m.getDeclaringClass().newInstance());
75.1 --- a/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Tue Jan 22 19:48:10 2013 +0100
75.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Wed Jan 23 12:53:23 2013 +0100
75.3 @@ -18,9 +18,6 @@
75.4 package org.apidesign.bck2brwsr.vmtest.impl;
75.5
75.6 import org.apidesign.bck2brwsr.vmtest.*;
75.7 -import java.io.File;
75.8 -import java.io.FileWriter;
75.9 -import java.io.IOException;
75.10 import java.lang.reflect.Method;
75.11 import java.util.ArrayList;
75.12 import java.util.List;
75.13 @@ -74,23 +71,8 @@
75.14 }
75.15
75.16 for (Method m : arr) {
75.17 - Compare c = m.getAnnotation(Compare.class);
75.18 - if (c == null) {
75.19 - continue;
75.20 - }
75.21 - final Bck2BrwsrCase real = new Bck2BrwsrCase(m, "Java", null);
75.22 - final Bck2BrwsrCase js = new Bck2BrwsrCase(m, "JavaScript", l.javaScript());
75.23 - ret.add(real);
75.24 - ret.add(js);
75.25 - ret.add(new CompareCase(m, real, js));
75.26 -
75.27 - for (String b : brwsr) {
75.28 - final Launcher s = l.brwsr(b);
75.29 - ret.add(s);
75.30 - final Bck2BrwsrCase cse = new Bck2BrwsrCase(m, b, s);
75.31 - ret.add(cse);
75.32 - ret.add(new CompareCase(m, real, cse));
75.33 - }
75.34 + registerCompareCases(m, l, ret, brwsr);
75.35 + registerBrwsrCases(m, l, ret, brwsr);
75.36 }
75.37 return ret.toArray();
75.38 }
75.39 @@ -123,4 +105,47 @@
75.40 public String getTestName() {
75.41 return m.getName() + "[Compare " + second.typeName() + "]";
75.42 }
75.43 +
75.44 + private static void registerCompareCases(Method m, final LaunchSetup l, List<Object> ret, String[] brwsr) {
75.45 + Compare c = m.getAnnotation(Compare.class);
75.46 + if (c == null) {
75.47 + return;
75.48 + }
75.49 + final Bck2BrwsrCase real = new Bck2BrwsrCase(m, "Java", null, false, null);
75.50 + ret.add(real);
75.51 + if (c.scripting()) {
75.52 + final Bck2BrwsrCase js = new Bck2BrwsrCase(m, "JavaScript", l.javaScript(), false, null);
75.53 + ret.add(js);
75.54 + ret.add(new CompareCase(m, real, js));
75.55 + }
75.56 + for (String b : brwsr) {
75.57 + final Launcher s = l.brwsr(b);
75.58 + ret.add(s);
75.59 + final Bck2BrwsrCase cse = new Bck2BrwsrCase(m, b, s, false, null);
75.60 + ret.add(cse);
75.61 + ret.add(new CompareCase(m, real, cse));
75.62 + }
75.63 + }
75.64 + private static void registerBrwsrCases(Method m, final LaunchSetup l, List<Object> ret, String[] brwsr) {
75.65 + BrwsrTest c = m.getAnnotation(BrwsrTest.class);
75.66 + if (c == null) {
75.67 + return;
75.68 + }
75.69 + HtmlFragment f = m.getAnnotation(HtmlFragment.class);
75.70 + if (f == null) {
75.71 + f = m.getDeclaringClass().getAnnotation(HtmlFragment.class);
75.72 + }
75.73 + String html = f == null ? null : f.value();
75.74 + if (brwsr.length == 0) {
75.75 + final Launcher s = l.brwsr(null);
75.76 + ret.add(s);
75.77 + ret.add(new Bck2BrwsrCase(m, "Brwsr", s, true, html));
75.78 + } else {
75.79 + for (String b : brwsr) {
75.80 + final Launcher s = l.brwsr(b);
75.81 + ret.add(s);
75.82 + ret.add(new Bck2BrwsrCase(m, b, s, true, html));
75.83 + }
75.84 + }
75.85 + }
75.86 }
76.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
76.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/AssertionTest.java Wed Jan 23 12:53:23 2013 +0100
76.3 @@ -0,0 +1,39 @@
76.4 +/**
76.5 + * Back 2 Browser Bytecode Translator
76.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
76.7 + *
76.8 + * This program is free software: you can redistribute it and/or modify
76.9 + * it under the terms of the GNU General Public License as published by
76.10 + * the Free Software Foundation, version 2 of the License.
76.11 + *
76.12 + * This program is distributed in the hope that it will be useful,
76.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
76.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
76.15 + * GNU General Public License for more details.
76.16 + *
76.17 + * You should have received a copy of the GNU General Public License
76.18 + * along with this program. Look for COPYING file in the top folder.
76.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
76.20 + */
76.21 +package org.apidesign.bck2brwsr.tck;
76.22 +
76.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
76.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
76.25 +import org.testng.annotations.Factory;
76.26 +
76.27 +/**
76.28 + *
76.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
76.30 + */
76.31 +public class AssertionTest {
76.32 +
76.33 + @Compare public Object checkAssert() throws ClassNotFoundException {
76.34 + assert false : "Is assertion status on?";
76.35 + return null;
76.36 + }
76.37 +
76.38 + @Factory
76.39 + public static Object[] create() {
76.40 + return VMTest.create(AssertionTest.class);
76.41 + }
76.42 +}
77.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
77.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/BrwsrCheckTest.java Wed Jan 23 12:53:23 2013 +0100
77.3 @@ -0,0 +1,57 @@
77.4 +/**
77.5 + * Back 2 Browser Bytecode Translator
77.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
77.7 + *
77.8 + * This program is free software: you can redistribute it and/or modify
77.9 + * it under the terms of the GNU General Public License as published by
77.10 + * the Free Software Foundation, version 2 of the License.
77.11 + *
77.12 + * This program is distributed in the hope that it will be useful,
77.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
77.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
77.15 + * GNU General Public License for more details.
77.16 + *
77.17 + * You should have received a copy of the GNU General Public License
77.18 + * along with this program. Look for COPYING file in the top folder.
77.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
77.20 + */
77.21 +package org.apidesign.bck2brwsr.tck;
77.22 +
77.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
77.24 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
77.25 +import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
77.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
77.27 +import org.testng.annotations.Factory;
77.28 +
77.29 +/**
77.30 + *
77.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
77.32 + */
77.33 +public class BrwsrCheckTest {
77.34 +
77.35 + @BrwsrTest public void assertWindowObjectIsDefined() {
77.36 + assert window() != null : "No window object found!";
77.37 + }
77.38 +
77.39 +
77.40 +
77.41 +
77.42 + @HtmlFragment("<h1 id='hello'>\n"
77.43 + + "Hello!\n"
77.44 + + "</h1>\n")
77.45 + @BrwsrTest public void accessProvidedFragment() {
77.46 + assert getElementById("hello") != null : "Element with 'hello' ID found";
77.47 + }
77.48 +
77.49 + @Factory
77.50 + public static Object[] create() {
77.51 + return VMTest.create(BrwsrCheckTest.class);
77.52 + }
77.53 +
77.54 +
77.55 + @JavaScriptBody(args = {}, body = "return window;")
77.56 + private static native Object window();
77.57 +
77.58 + @JavaScriptBody(args = { "id" }, body = "return window.document.getElementById(id);")
77.59 + private static native Object getElementById(String id);
77.60 +}
78.1 --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Tue Jan 22 19:48:10 2013 +0100
78.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Wed Jan 23 12:53:23 2013 +0100
78.3 @@ -42,6 +42,10 @@
78.4 return String.class.cast(o);
78.5 }
78.6
78.7 + @Compare public boolean equalToNull() {
78.8 + return "Ahoj".equals(null);
78.9 + }
78.10 +
78.11 @Compare public static Object compareURLs() throws MalformedURLException {
78.12 return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString();
78.13 }
79.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
79.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java Wed Jan 23 12:53:23 2013 +0100
79.3 @@ -0,0 +1,135 @@
79.4 +/**
79.5 + * Back 2 Browser Bytecode Translator
79.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
79.7 + *
79.8 + * This program is free software: you can redistribute it and/or modify
79.9 + * it under the terms of the GNU General Public License as published by
79.10 + * the Free Software Foundation, version 2 of the License.
79.11 + *
79.12 + * This program is distributed in the hope that it will be useful,
79.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
79.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79.15 + * GNU General Public License for more details.
79.16 + *
79.17 + * You should have received a copy of the GNU General Public License
79.18 + * along with this program. Look for COPYING file in the top folder.
79.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
79.20 + */
79.21 +package org.apidesign.bck2brwsr.tck;
79.22 +
79.23 +import java.lang.reflect.Array;
79.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
79.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
79.26 +import org.testng.annotations.Factory;
79.27 +
79.28 +/**
79.29 + *
79.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
79.31 + */
79.32 +public class ReflectionArrayTest {
79.33 + @Compare public int lengthOfStringArray() {
79.34 + String[] arr = (String[]) Array.newInstance(String.class, 10);
79.35 + return arr.length;
79.36 + }
79.37 +
79.38 + @Compare public int reflectiveLengthOfStringArray() {
79.39 + Object arr = Array.newInstance(String.class, 10);
79.40 + return Array.getLength(arr);
79.41 + }
79.42 +
79.43 + @Compare public int reflectiveLengthOneNonArray() {
79.44 + Object arr = "non-array";
79.45 + return Array.getLength(arr);
79.46 + }
79.47 +
79.48 + @Compare public String compTypeOfStringArray() {
79.49 + String[] arr = (String[]) Array.newInstance(String.class, 10);
79.50 + return arr.getClass().getComponentType().getName();
79.51 + }
79.52 +
79.53 + @Compare public Object negativeArrayExcp() {
79.54 + return Array.newInstance(String.class, -5);
79.55 + }
79.56 +
79.57 + @Compare public int lengthOfIntArray() {
79.58 + int[] arr = (int[]) Array.newInstance(Integer.TYPE, 10);
79.59 + return arr.length;
79.60 + }
79.61 +
79.62 + @Compare public int reflectiveLengthOfIntArray() {
79.63 + Object arr = Array.newInstance(Integer.TYPE, 10);
79.64 + return Array.getLength(arr);
79.65 + }
79.66 +
79.67 + @Compare public String compTypeOfIntArray() {
79.68 + int[] arr = (int[]) Array.newInstance(int.class, 10);
79.69 + return arr.getClass().getComponentType().getName();
79.70 + }
79.71 +
79.72 + @Compare public Object intNegativeArrayExcp() {
79.73 + return Array.newInstance(int.class, -5);
79.74 + }
79.75 +
79.76 + @Compare public Integer verifyAutobox() {
79.77 + int[] arr = (int[]) Array.newInstance(int.class, 5);
79.78 + return (Integer) Array.get(arr, 0);
79.79 + }
79.80 + @Compare public String verifyObjectArray() {
79.81 + String[] arr = (String[]) Array.newInstance(String.class, 5);
79.82 + Array.set(arr, 0, "Hello");
79.83 + return (String) Array.get(arr, 0);
79.84 + }
79.85 + @Compare public int verifyInt() {
79.86 + int[] arr = (int[]) Array.newInstance(int.class, 5);
79.87 + return Array.getInt(arr, 0);
79.88 + }
79.89 + @Compare public long verifyConvertToLong() {
79.90 + int[] arr = (int[]) Array.newInstance(int.class, 5);
79.91 + return Array.getLong(arr, 0);
79.92 + }
79.93 +
79.94 + @Compare public Object verifySetIntToObject() {
79.95 + try {
79.96 + Object[] arr = (Object[]) Array.newInstance(Object.class, 5);
79.97 + Array.setInt(arr, 0, 10);
79.98 + return Array.get(arr, 0);
79.99 + } catch (Exception exception) {
79.100 + return exception.getClass().getName();
79.101 + }
79.102 + }
79.103 + @Compare public long verifySetShort() {
79.104 + int[] arr = (int[]) Array.newInstance(int.class, 5);
79.105 + Array.setShort(arr, 0, (short)10);
79.106 + return Array.getLong(arr, 0);
79.107 + }
79.108 + @Compare public long verifyCantSetLong() {
79.109 + int[] arr = (int[]) Array.newInstance(int.class, 5);
79.110 + Array.setLong(arr, 0, 10);
79.111 + return Array.getLong(arr, 0);
79.112 + }
79.113 + @Compare public float verifyLongToFloat() {
79.114 + Object arr = Array.newInstance(float.class, 5);
79.115 + Array.setLong(arr, 0, 10);
79.116 + return Array.getFloat(arr, 0);
79.117 + }
79.118 +
79.119 + @Compare public double verifyConvertToDouble() {
79.120 + int[] arr = (int[]) Array.newInstance(int.class, 5);
79.121 + return Array.getDouble(arr, 0);
79.122 + }
79.123 +
79.124 + @Compare public int multiIntArray() {
79.125 + int[][][] arr = (int[][][]) Array.newInstance(int.class, 3, 3, 3);
79.126 + return arr[0][1][2] + 5 + arr[2][2][0];
79.127 + }
79.128 +
79.129 + @Compare public String multiIntArrayCompType() {
79.130 + return Array.newInstance(int.class, 3, 3, 3).getClass().getName();
79.131 + }
79.132 +
79.133 +
79.134 + @Factory
79.135 + public static Object[] create() {
79.136 + return VMTest.create(ReflectionArrayTest.class);
79.137 + }
79.138 +}