#258088: Non-mutable values aren't wrapped into ko.observable, but rather stored as primitive values
1.1 --- a/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java Mon Feb 22 06:09:33 2016 +0100
1.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java Mon Feb 22 19:58:32 2016 +0100
1.3 @@ -73,14 +73,14 @@
1.4 @Property(name="choice", type=KnockoutTest.Choice.class),
1.5 @Property(name="archetype", type=ArchetypeData.class),
1.6 @Property(name="archetypes", type=ArchetypeData.class, array = true),
1.7 -})
1.8 +})
1.9 public final class KnockoutTest {
1.10 private KnockoutModel js;
1.11 -
1.12 +
1.13 enum Choice {
1.14 A, B;
1.15 }
1.16 -
1.17 +
1.18 @ComputedProperty static List<Integer> resultLengths(List<String> results) {
1.19 Integer[] arr = new Integer[results.size()];
1.20 for (int i = 0; i < arr.length; i++) {
1.21 @@ -88,9 +88,9 @@
1.22 }
1.23 return Arrays.asList(arr);
1.24 }
1.25 -
1.26 +
1.27 @KOTest public void modifyValueAssertChangeInModelOnEnum() throws Throwable {
1.28 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.29 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.30 "Latitude: <input id='input' data-bind=\"value: choice\"></input>\n"
1.31 );
1.32 try {
1.33 @@ -143,9 +143,9 @@
1.34 Utils.exposeHTML(KnockoutTest.class, "");
1.35 }
1.36 }
1.37 -
1.38 +
1.39 @KOTest public void modifyValueAssertChangeInModelOnDouble() throws Throwable {
1.40 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.41 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.42 "Latitude: <input id='input' data-bind=\"value: latitude\"></input>\n"
1.43 );
1.44 try {
1.45 @@ -167,7 +167,7 @@
1.46 Utils.exposeHTML(KnockoutTest.class, "");
1.47 }
1.48 }
1.49 -
1.50 +
1.51 @KOTest public void rawObject() throws Exception {
1.52 if (js == null) {
1.53 final BrwsrCtx ctx = newContext();
1.54 @@ -200,7 +200,7 @@
1.55
1.56 p1.setFirstName("Ondra");
1.57 assertEquals(p1.getFirstName(), "Ondra", "1st name updated in original object");
1.58 -
1.59 +
1.60 js.getPeople().add(p1);
1.61 }
1.62
1.63 @@ -239,9 +239,9 @@
1.64 Utils.exposeHTML(KnockoutTest.class, "");
1.65 }
1.66 }
1.67 -
1.68 +
1.69 @KOTest public void modifyValueAssertChangeInModelOnBoolean() throws Throwable {
1.70 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.71 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.72 "Latitude: <input id='input' data-bind=\"value: enabled\"></input>\n"
1.73 );
1.74 try {
1.75 @@ -263,9 +263,9 @@
1.76 Utils.exposeHTML(KnockoutTest.class, "");
1.77 }
1.78 }
1.79 -
1.80 +
1.81 @KOTest public void modifyValueAssertChangeInModel() throws Exception {
1.82 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.83 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.84 "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
1.85 "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
1.86 "<button id=\"hello\">Say Hello!</button>\n"
1.87 @@ -287,7 +287,7 @@
1.88 Utils.exposeHTML(KnockoutTest.class, "");
1.89 }
1.90 }
1.91 -
1.92 +
1.93 private static String getSetSelected(int index, Object value) throws Exception {
1.94 String s = "var index = arguments[0];\n"
1.95 + "var value = arguments[1];\n"
1.96 @@ -305,7 +305,7 @@
1.97 );
1.98 return ret == null ? null : ret.toString();
1.99 }
1.100 -
1.101 +
1.102 @Model(className = "ArchetypeData", properties = {
1.103 @Property(name = "artifactId", type = String.class),
1.104 @Property(name = "groupId", type = String.class),
1.105 @@ -316,35 +316,35 @@
1.106 })
1.107 static class ArchModel {
1.108 }
1.109 -
1.110 +
1.111 @KOTest public void selectWorksOnModels() throws Exception {
1.112 if (js == null) {
1.113 - Utils.exposeHTML(KnockoutTest.class,
1.114 + Utils.exposeHTML(KnockoutTest.class,
1.115 "<select id='input' data-bind=\"options: archetypes,\n" +
1.116 " optionsText: 'name',\n" +
1.117 " value: archetype\">\n" +
1.118 " </select>\n" +
1.119 ""
1.120 );
1.121 -
1.122 +
1.123 js = Models.bind(new KnockoutModel(), newContext());
1.124 js.getArchetypes().add(new ArchetypeData("ko4j", "org.netbeans.html", "0.8.3", "ko4j", "ko4j", null));
1.125 js.getArchetypes().add(new ArchetypeData("crud", "org.netbeans.html", "0.8.3", "crud", "crud", null));
1.126 js.getArchetypes().add(new ArchetypeData("3rd", "org.netbeans.html", "0.8.3", "3rd", "3rd", null));
1.127 js.setArchetype(js.getArchetypes().get(1));
1.128 js.applyBindings();
1.129 -
1.130 +
1.131 String v = getSetSelected(0, null);
1.132 assertEquals("crud", v, "Second index (e.g. crud) is selected: " + v);
1.133 -
1.134 +
1.135 String sel = getSetSelected(2, Models.toRaw(js.getArchetypes().get(2)));
1.136 assertEquals("3rd", sel, "3rd is selected now: " + sel);
1.137 }
1.138 -
1.139 +
1.140 if (js.getArchetype() != js.getArchetypes().get(2)) {
1.141 throw new InterruptedException();
1.142 }
1.143 -
1.144 +
1.145 Utils.exposeHTML(KnockoutTest.class, "");
1.146 }
1.147
1.148 @@ -374,22 +374,22 @@
1.149 assertEquals("org.netbeans.html", v, "groupId has been changed");
1.150 Utils.exposeHTML(KnockoutTest.class, "");
1.151 }
1.152 -
1.153 +
1.154 @KOTest public void modifyValueAssertAsyncChangeInModel() throws Exception {
1.155 if (js == null) {
1.156 - Utils.exposeHTML(KnockoutTest.class,
1.157 + Utils.exposeHTML(KnockoutTest.class,
1.158 "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
1.159 "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
1.160 "<button id=\"hello\">Say Hello!</button>\n"
1.161 );
1.162 -
1.163 +
1.164 js = Models.bind(new KnockoutModel(), newContext());
1.165 js.setName("Kukuc");
1.166 js.applyBindings();
1.167 -
1.168 +
1.169 String v = getSetInput("input", null);
1.170 assertEquals("Kukuc", v, "Value is really kukuc: " + v);
1.171 -
1.172 +
1.173 Timer t = new Timer("Set to Jardo");
1.174 t.schedule(new TimerTask() {
1.175 @Override
1.176 @@ -398,15 +398,100 @@
1.177 }
1.178 }, 1);
1.179 }
1.180 -
1.181 +
1.182 String v = getSetInput("input", null);
1.183 if (!"Jardo".equals(v)) {
1.184 throw new InterruptedException();
1.185 }
1.186 -
1.187 +
1.188 Utils.exposeHTML(KnockoutTest.class, "");
1.189 }
1.190 -
1.191 +
1.192 + @Model(className = "ConstantModel", targetId = "", builder = "assign", properties = {
1.193 + @Property(name = "doubleValue", mutable = false, type = double.class),
1.194 + @Property(name = "longValue", mutable = false, type = long.class),
1.195 + @Property(name = "stringValue", mutable = false, type = String.class),
1.196 + @Property(name = "boolValue", mutable = false, type = boolean.class),
1.197 + @Property(name = "intArray", mutable = false, type = int.class, array = true),
1.198 + })
1.199 + static class ConstantCntrl {
1.200 + }
1.201 +
1.202 + @KOTest public void nonMutableDouble() throws Exception {
1.203 + Utils.exposeHTML(KnockoutTest.class,
1.204 + "Type: <input id='input' data-bind=\"value: typeof doubleValue\"></input>\n"
1.205 + );
1.206 +
1.207 + ConstantModel model = Models.bind(new ConstantModel(), newContext());
1.208 + model.assignStringValue("Hello").assignDoubleValue(10.0);
1.209 + model.applyBindings();
1.210 +
1.211 + String v = getSetInput("input", null);
1.212 + assertEquals(v, "number", "Right type found: " + v);
1.213 +
1.214 + Utils.exposeHTML(KnockoutTest.class, "");
1.215 + }
1.216 +
1.217 + @KOTest public void nonMutableString() throws Exception {
1.218 + Utils.exposeHTML(KnockoutTest.class,
1.219 + "Type: <input id='input' data-bind=\"value: typeof stringValue\"></input>\n"
1.220 + );
1.221 +
1.222 + ConstantModel model = Models.bind(new ConstantModel(), newContext());
1.223 + model.assignStringValue("Hello").assignDoubleValue(10.0);
1.224 + model.applyBindings();
1.225 +
1.226 + String v = getSetInput("input", null);
1.227 + assertEquals(v, "string", "Right type found: " + v);
1.228 +
1.229 + Utils.exposeHTML(KnockoutTest.class, "");
1.230 + }
1.231 +
1.232 + @KOTest public void nonMutableBoolean() throws Exception {
1.233 + Utils.exposeHTML(KnockoutTest.class,
1.234 + "Type: <input id='input' data-bind=\"value: typeof boolValue\"></input>\n"
1.235 + );
1.236 +
1.237 + ConstantModel model = Models.bind(new ConstantModel(), newContext());
1.238 + model.assignStringValue("Hello").assignBoolValue(true);
1.239 + model.applyBindings();
1.240 +
1.241 + String v = getSetInput("input", null);
1.242 + assertEquals(v, "boolean", "Right type found: " + v);
1.243 +
1.244 + Utils.exposeHTML(KnockoutTest.class, "");
1.245 + }
1.246 +
1.247 + @KOTest public void nonMutableLong() throws Exception {
1.248 + Utils.exposeHTML(KnockoutTest.class,
1.249 + "Type: <input id='input' data-bind=\"value: typeof longValue\"></input>\n"
1.250 + );
1.251 +
1.252 + ConstantModel model = Models.bind(new ConstantModel(), newContext());
1.253 + model.assignStringValue("Hello").assignLongValue(Long.MAX_VALUE);
1.254 + model.applyBindings();
1.255 +
1.256 + String v = getSetInput("input", null);
1.257 + assertEquals(v, "number", "Right type found: " + v);
1.258 +
1.259 + Utils.exposeHTML(KnockoutTest.class, "");
1.260 + }
1.261 +
1.262 + @KOTest public void nonMutableIntArray() throws Exception {
1.263 + Utils.exposeHTML(KnockoutTest.class,
1.264 + "Type: <input id='input' data-bind=\"value: typeof intArray\"></input>\n"
1.265 + );
1.266 +
1.267 + ConstantModel model = Models.bind(new ConstantModel(), newContext());
1.268 + model.assignStringValue("Hello").assignLongValue(Long.MAX_VALUE).assignIntArray(1, 2, 3, 4);
1.269 + model.applyBindings();
1.270 +
1.271 + String v = getSetInput("input", null);
1.272 + assertEquals(v, "object", "Right type found: " + v);
1.273 +
1.274 + Utils.exposeHTML(KnockoutTest.class, "");
1.275 + }
1.276 +
1.277 private static String getSetInput(String id, String value) throws Exception {
1.278 String s = "var value = arguments[0];\n"
1.279 + "var n = window.document.getElementById(arguments[1]); \n "
1.280 @@ -429,7 +514,7 @@
1.281 );
1.282 return Boolean.TRUE.equals(ret);
1.283 }
1.284 -
1.285 +
1.286 public static void triggerEvent(String id, String ev) throws Exception {
1.287 Utils.executeScript(
1.288 KnockoutTest.class,
1.289 @@ -437,9 +522,9 @@
1.290 id, ev
1.291 );
1.292 }
1.293 -
1.294 +
1.295 @KOTest public void displayContentOfArray() throws Exception {
1.296 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.297 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.298 "<ul id='ul' data-bind='foreach: results'>\n"
1.299 + " <li data-bind='text: $data, click: $root.call'/>\n"
1.300 + "</ul>\n"
1.301 @@ -465,10 +550,10 @@
1.302 Utils.exposeHTML(KnockoutTest.class, "");
1.303 }
1.304 }
1.305 -
1.306 +
1.307 @KOTest public void displayContentOfAsyncArray() throws Exception {
1.308 if (js == null) {
1.309 - Utils.exposeHTML(KnockoutTest.class,
1.310 + Utils.exposeHTML(KnockoutTest.class,
1.311 "<ul id='ul' data-bind='foreach: results'>\n"
1.312 + " <li data-bind='text: $data, click: $root.call'/>\n"
1.313 + "</ul>\n"
1.314 @@ -479,7 +564,7 @@
1.315
1.316 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
1.317 assertEquals(cnt, 1, "One child, but was " + cnt);
1.318 -
1.319 +
1.320 Timer t = new Timer("add to array");
1.321 t.schedule(new TimerTask() {
1.322 @Override
1.323 @@ -504,9 +589,9 @@
1.324 Utils.exposeHTML(KnockoutTest.class, "");
1.325 }
1.326 }
1.327 -
1.328 +
1.329 @KOTest public void displayContentOfComputedArray() throws Exception {
1.330 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.331 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.332 "<ul id='ul' data-bind='foreach: bothNames'>\n"
1.333 + " <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
1.334 + "</ul>\n"
1.335 @@ -521,23 +606,23 @@
1.336 triggerChildClick("ul", 1);
1.337
1.338 assertEquals("Last", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
1.339 -
1.340 +
1.341 m.setLastName("Verylast");
1.342
1.343 cnt = Utils.countChildren(KnockoutTest.class, "ul");
1.344 assertEquals(cnt, 2, "Two children now, but was " + cnt);
1.345 -
1.346 +
1.347 triggerChildClick("ul", 1);
1.348
1.349 assertEquals("Verylast", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
1.350 -
1.351 +
1.352 } finally {
1.353 Utils.exposeHTML(KnockoutTest.class, "");
1.354 }
1.355 }
1.356 -
1.357 +
1.358 @KOTest public void displayContentOfComputedArrayOnASubpair() throws Exception {
1.359 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.360 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.361 "<div data-bind='with: next'>\n"
1.362 + "<ul id='ul' data-bind='foreach: bothNames'>\n"
1.363 + " <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
1.364 @@ -553,7 +638,7 @@
1.365 assertEquals(cnt, 2, "Two children now, but was " + cnt);
1.366
1.367 triggerChildClick("ul", 1);
1.368 -
1.369 +
1.370 assertEquals(PairModel.ctx, ctx, "Context remains the same");
1.371
1.372 assertEquals("Last", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
1.373 @@ -561,9 +646,9 @@
1.374 Utils.exposeHTML(KnockoutTest.class, "");
1.375 }
1.376 }
1.377 -
1.378 +
1.379 @KOTest public void displayContentOfComputedArrayOnComputedASubpair() throws Exception {
1.380 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.381 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.382 "<div data-bind='with: nextOne'>\n"
1.383 + "<ul id='ul' data-bind='foreach: bothNames'>\n"
1.384 + " <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
1.385 @@ -586,7 +671,7 @@
1.386 }
1.387
1.388 @KOTest public void checkBoxToBooleanBinding() throws Exception {
1.389 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.390 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.391 "<input type='checkbox' id='b' data-bind='checked: enabled'></input>\n"
1.392 );
1.393 try {
1.394 @@ -602,11 +687,11 @@
1.395 Utils.exposeHTML(KnockoutTest.class, "");
1.396 }
1.397 }
1.398 -
1.399 -
1.400 -
1.401 +
1.402 +
1.403 +
1.404 @KOTest public void displayContentOfDerivedArray() throws Exception {
1.405 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.406 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.407 "<ul id='ul' data-bind='foreach: cmpResults'>\n"
1.408 + " <li><b data-bind='text: $data'></b></li>\n"
1.409 + "</ul>\n"
1.410 @@ -627,9 +712,9 @@
1.411 Utils.exposeHTML(KnockoutTest.class, "");
1.412 }
1.413 }
1.414 -
1.415 +
1.416 @KOTest public void displayContentOfArrayOfPeople() throws Exception {
1.417 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.418 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.419 "<ul id='ul' data-bind='foreach: people'>\n"
1.420 + " <li data-bind='text: $data.firstName, click: $root.removePerson'></li>\n"
1.421 + "</ul>\n"
1.422 @@ -672,14 +757,14 @@
1.423 Utils.exposeHTML(KnockoutTest.class, "");
1.424 }
1.425 }
1.426 -
1.427 +
1.428 @ComputedProperty
1.429 static Person firstPerson(List<Person> people) {
1.430 return people.isEmpty() ? null : people.get(0);
1.431 }
1.432 -
1.433 +
1.434 @KOTest public void accessFirstPersonWithOnFunction() throws Exception {
1.435 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.436 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.437 "<p id='ul' data-bind='with: firstPerson'>\n"
1.438 + " <span data-bind='text: firstName, click: changeSex'></span>\n"
1.439 + "</p>\n"
1.440 @@ -690,9 +775,9 @@
1.441 Utils.exposeHTML(KnockoutTest.class, "");
1.442 }
1.443 }
1.444 -
1.445 +
1.446 @KOTest public void onPersonFunction() throws Exception {
1.447 - Object exp = Utils.exposeHTML(KnockoutTest.class,
1.448 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.449 "<ul id='ul' data-bind='foreach: people'>\n"
1.450 + " <li data-bind='text: $data.firstName, click: changeSex'></li>\n"
1.451 + "</ul>\n"
1.452 @@ -703,7 +788,7 @@
1.453 Utils.exposeHTML(KnockoutTest.class, "");
1.454 }
1.455 }
1.456 -
1.457 +
1.458 private void trasfertToFemale() throws Exception {
1.459 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
1.460
1.461 @@ -723,7 +808,7 @@
1.462
1.463 assertEquals(first.getSex(), Sex.FEMALE, "Transverted to female: " + first.getSex());
1.464 }
1.465 -
1.466 +
1.467 @KOTest public void stringArrayModificationVisible() throws Exception {
1.468 Object exp = Utils.exposeHTML(KnockoutTest.class,
1.469 "<div>\n"
1.470 @@ -737,19 +822,19 @@
1.471 m.getResults().add("Ahoj");
1.472 m.getResults().add("Hello");
1.473 m.applyBindings();
1.474 -
1.475 +
1.476 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
1.477 assertEquals(cnt, 2, "Two children " + cnt);
1.478 -
1.479 +
1.480 Object arr = Utils.addChildren(KnockoutTest.class, "ul", "results", "Hi");
1.481 assertTrue(arr instanceof Object[], "Got back an array: " + arr);
1.482 final int len = ((Object[])arr).length;
1.483 -
1.484 +
1.485 assertEquals(len, 3, "Three elements in the array " + len);
1.486 -
1.487 +
1.488 int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
1.489 assertEquals(newCnt, 3, "Three children in the DOM: " + newCnt);
1.490 -
1.491 +
1.492 assertEquals(m.getResults().size(), 3, "Three java strings: " + m.getResults());
1.493 } finally {
1.494 Utils.exposeHTML(KnockoutTest.class, "");
1.495 @@ -769,19 +854,19 @@
1.496 m.getNumbers().add(1);
1.497 m.getNumbers().add(31);
1.498 m.applyBindings();
1.499 -
1.500 +
1.501 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
1.502 assertEquals(cnt, 2, "Two children " + cnt);
1.503 -
1.504 +
1.505 Object arr = Utils.addChildren(KnockoutTest.class, "ul", "numbers", 42);
1.506 assertTrue(arr instanceof Object[], "Got back an array: " + arr);
1.507 final int len = ((Object[])arr).length;
1.508 -
1.509 +
1.510 assertEquals(len, 3, "Three elements in the array " + len);
1.511 -
1.512 +
1.513 int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
1.514 assertEquals(newCnt, 3, "Three children in the DOM: " + newCnt);
1.515 -
1.516 +
1.517 assertEquals(m.getNumbers().size(), 3, "Three java ints: " + m.getNumbers());
1.518 assertEquals(m.getNumbers().get(2), 42, "Meaning of world: " + m.getNumbers());
1.519 } finally {
1.520 @@ -802,26 +887,26 @@
1.521 m.getResults().add("Ahoj");
1.522 m.getResults().add("Hello");
1.523 m.applyBindings();
1.524 -
1.525 +
1.526 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
1.527 assertEquals(cnt, 2, "Two children " + cnt);
1.528 -
1.529 +
1.530 Object arr = Utils.addChildren(KnockoutTest.class, "ul", "results", "Hi");
1.531 assertTrue(arr instanceof Object[], "Got back an array: " + arr);
1.532 final int len = ((Object[])arr).length;
1.533 -
1.534 +
1.535 assertEquals(len, 3, "Three elements in the array " + len);
1.536 -
1.537 +
1.538 int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
1.539 assertEquals(newCnt, 3, "Three children in the DOM: " + newCnt);
1.540 -
1.541 +
1.542 assertEquals(m.getResultLengths().size(), 3, "Three java ints: " + m.getResultLengths());
1.543 assertEquals(m.getResultLengths().get(2), 2, "Size is two: " + m.getResultLengths());
1.544 } finally {
1.545 Utils.exposeHTML(KnockoutTest.class, "");
1.546 }
1.547 }
1.548 -
1.549 +
1.550 @KOTest public void archetypeArrayModificationVisible() throws Exception {
1.551 Object exp = Utils.exposeHTML(KnockoutTest.class,
1.552 "<div>\n"
1.553 @@ -833,19 +918,19 @@
1.554 try {
1.555 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
1.556 m.applyBindings();
1.557 -
1.558 +
1.559 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
1.560 assertEquals(cnt, 0, "No children " + cnt);
1.561 -
1.562 +
1.563 Object arr = Utils.addChildren(KnockoutTest.class, "ul", "archetypes", new ArchetypeData("aid", "gid", "v", "n", "d", "u"));
1.564 assertTrue(arr instanceof Object[], "Got back an array: " + arr);
1.565 final int len = ((Object[])arr).length;
1.566 -
1.567 +
1.568 assertEquals(len, 1, "One element in the array " + len);
1.569 -
1.570 +
1.571 int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
1.572 assertEquals(newCnt, 1, "One child in the DOM: " + newCnt);
1.573 -
1.574 +
1.575 assertEquals(m.getArchetypes().size(), 1, "One archetype: " + m.getArchetypes());
1.576 assertNotNull(m.getArchetypes().get(0), "Not null: " + m.getArchetypes());
1.577 assertEquals(m.getArchetypes().get(0).getArtifactId(), "aid", "'aid' == " + m.getArchetypes());
1.578 @@ -865,18 +950,18 @@
1.579 model.setCallbackCount(model.getCallbackCount() + 1);
1.580 model.getPeople().remove(data);
1.581 }
1.582 -
1.583 -
1.584 +
1.585 +
1.586 @ComputedProperty
1.587 static String helloMessage(String name) {
1.588 return "Hello " + name + "!";
1.589 }
1.590 -
1.591 +
1.592 @ComputedProperty
1.593 static List<String> cmpResults(List<String> results) {
1.594 return results;
1.595 }
1.596 -
1.597 +
1.598 private static void triggerClick(String id) throws Exception {
1.599 String s = "var id = arguments[0];"
1.600 + "var e = window.document.getElementById(id);\n "
1.601 @@ -893,17 +978,17 @@
1.602 s, id);
1.603 }
1.604 private static void triggerChildClick(String id, int pos) throws Exception {
1.605 - String s =
1.606 + String s =
1.607 "var id = arguments[0]; var pos = arguments[1];\n" +
1.608 "var e = window.document.getElementById(id);\n " +
1.609 "var ev = window.document.createEvent('MouseEvents');\n " +
1.610 "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n " +
1.611 "var list = e.childNodes;\n" +
1.612 - "var cnt = -1;\n" +
1.613 - "for (var i = 0; i < list.length; i++) {\n" +
1.614 - " if (list[i].nodeType == 1) cnt++;\n" +
1.615 - " if (cnt == pos) return list[i].dispatchEvent(ev);\n" +
1.616 - "}\n" +
1.617 + "var cnt = -1;\n" +
1.618 + "for (var i = 0; i < list.length; i++) {\n" +
1.619 + " if (list[i].nodeType == 1) cnt++;\n" +
1.620 + " if (cnt == pos) return list[i].dispatchEvent(ev);\n" +
1.621 + "}\n" +
1.622 "return null;\n";
1.623 Utils.executeScript(
1.624 KnockoutTest.class,
1.625 @@ -911,15 +996,15 @@
1.626 }
1.627
1.628 private static String childText(String id, int pos) throws Exception {
1.629 - String s =
1.630 + String s =
1.631 "var id = arguments[0]; var pos = arguments[1];" +
1.632 "var e = window.document.getElementById(id);\n" +
1.633 "var list = e.childNodes;\n" +
1.634 - "var cnt = -1;\n" +
1.635 - "for (var i = 0; i < list.length; i++) {\n" +
1.636 - " if (list[i].nodeType == 1) cnt++;\n" +
1.637 - " if (cnt == pos) return list[i].innerHTML;\n" +
1.638 - "}\n" +
1.639 + "var cnt = -1;\n" +
1.640 + "for (var i = 0; i < list.length; i++) {\n" +
1.641 + " if (list[i].nodeType == 1) cnt++;\n" +
1.642 + " if (cnt == pos) return list[i].innerHTML;\n" +
1.643 + "}\n" +
1.644 "return null;\n";
1.645 return (String)Utils.executeScript(
1.646 KnockoutTest.class,
2.1 --- a/json/src/main/java/org/netbeans/html/json/impl/Bindings.java Mon Feb 22 06:09:33 2016 +0100
2.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java Mon Feb 22 19:58:32 2016 +0100
2.3 @@ -64,8 +64,8 @@
2.4 this.bp = bp;
2.5 }
2.6
2.7 - public <M> PropertyBinding registerProperty(String propName, int index, M model, Proto.Type<M> access, boolean readOnly) {
2.8 - return PropertyBindingAccessor.create(access, this, propName, index, model, readOnly);
2.9 + public <M> PropertyBinding registerProperty(String propName, int index, M model, Proto.Type<M> access, byte propertyType) {
2.10 + return PropertyBindingAccessor.create(access, this, propName, index, model, propertyType);
2.11 }
2.12
2.13 public static Bindings<?> apply(BrwsrCtx c) {
3.1 --- a/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Mon Feb 22 06:09:33 2016 +0100
3.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Mon Feb 22 19:58:32 2016 +0100
3.3 @@ -359,7 +359,7 @@
3.4 {
3.5 for (int i = 0; i < propsGetSet.size(); i++) {
3.6 w.append(" registerProperty(\"").append(propsGetSet.get(i).name).append("\", ");
3.7 - w.append((i) + ", " + propsGetSet.get(i).readOnly + ");\n");
3.8 + w.append((i) + ", " + propsGetSet.get(i).readOnly + ", " + propsGetSet.get(i).constant + ");\n");
3.9 }
3.10 }
3.11 {
3.12 @@ -728,7 +728,8 @@
3.13 gs[0],
3.14 gs[1],
3.15 tn,
3.16 - gs[3] == null && !p.array()
3.17 + gs[3] == null && !p.array(),
3.18 + !p.mutable()
3.19 ));
3.20 }
3.21 return ok;
3.22 @@ -864,7 +865,8 @@
3.23 gs[0],
3.24 null,
3.25 tn,
3.26 - true
3.27 + true,
3.28 + false
3.29 ));
3.30 } else {
3.31 w.write(" public void " + gs[4] + "(" + write.getParameters().get(1).asType());
3.32 @@ -877,6 +879,7 @@
3.33 gs[0],
3.34 gs[4],
3.35 tn,
3.36 + false,
3.37 false
3.38 ));
3.39 }
3.40 @@ -2069,12 +2072,15 @@
3.41 final String setter;
3.42 final String type;
3.43 final boolean readOnly;
3.44 - GetSet(String name, String getter, String setter, String type, boolean readOnly) {
3.45 + final boolean constant;
3.46 +
3.47 + GetSet(String name, String getter, String setter, String type, boolean readOnly, boolean constant) {
3.48 this.name = name;
3.49 this.getter = getter;
3.50 this.setter = setter;
3.51 this.type = type;
3.52 this.readOnly = readOnly;
3.53 + this.constant = constant;
3.54 }
3.55 }
3.56
4.1 --- a/json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java Mon Feb 22 06:09:33 2016 +0100
4.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java Mon Feb 22 19:58:32 2016 +0100
4.3 @@ -64,8 +64,7 @@
4.4 }
4.5
4.6 protected abstract <M> PropertyBinding newBinding(
4.7 - Proto.Type<M> access, Bindings<?> bindings, String name, int index, M model, boolean readOnly
4.8 - );
4.9 + Proto.Type<M> access, Bindings<?> bindings, String name, int index, M model, byte propertyType);
4.10 protected abstract JSONCall newCall(
4.11 BrwsrCtx ctx, RcvrJSON callback,
4.12 String headers, String urlBefore, String urlAfter,
4.13 @@ -87,9 +86,9 @@
4.14 }
4.15
4.16 static <M> PropertyBinding create(
4.17 - Proto.Type<M> access, Bindings<?> bindings, String name, int index, M model , boolean readOnly
4.18 + Proto.Type<M> access, Bindings<?> bindings, String name, int index, M model , byte propertyType
4.19 ) {
4.20 - return DEFAULT.newBinding(access, bindings, name, index, model, readOnly);
4.21 + return DEFAULT.newBinding(access, bindings, name, index, model, propertyType);
4.22 }
4.23 public static JSONCall createCall(
4.24 BrwsrCtx ctx, RcvrJSON callback,
5.1 --- a/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java Mon Feb 22 06:09:33 2016 +0100
5.2 +++ b/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java Mon Feb 22 19:58:32 2016 +0100
5.3 @@ -45,6 +45,7 @@
5.4 import java.lang.ref.Reference;
5.5 import java.lang.ref.WeakReference;
5.6 import net.java.html.BrwsrCtx;
5.7 +import net.java.html.json.ComputedProperty;
5.8 import org.netbeans.html.json.impl.Bindings;
5.9 import org.netbeans.html.json.impl.JSON;
5.10 import org.netbeans.html.json.impl.PropertyBindingAccessor;
5.11 @@ -93,10 +94,8 @@
5.12
5.13 @Override
5.14 protected <M> PropertyBinding newBinding(
5.15 - Proto.Type<M> access, Bindings<?> bindings, String name,
5.16 - int index, M model, boolean readOnly
5.17 - ) {
5.18 - return new Impl(model, bindings, name, index, access, readOnly);
5.19 + Proto.Type<M> access, Bindings<?> bindings, String name, int index, M model, byte propertyType) {
5.20 + return new Impl(model, bindings, name, index, access, propertyType);
5.21 }
5.22 };
5.23 }
5.24 @@ -121,12 +120,22 @@
5.25 */
5.26 public abstract Object getValue();
5.27
5.28 - /** Is this property read only? Or can one call {@link #setValue(java.lang.Object)}?
5.29 + /** Is this property read only?. Or can one call {@link #setValue(java.lang.Object)}?
5.30 + * The property can still change, but only as a result of other
5.31 + * properties being changed, just like {@link ComputedProperty} can.
5.32 *
5.33 * @return true, if this property is read only
5.34 */
5.35 public abstract boolean isReadOnly();
5.36
5.37 + /** Is this property constant?. If a property is constant, than its
5.38 + * value cannot changed after it is read.
5.39 + *
5.40 + * @return true, if this property is constant
5.41 + * @since 1.3
5.42 + */
5.43 + public abstract boolean isConstant();
5.44 +
5.45 /** Returns identical version of the binding, but one that holds on the
5.46 * original model object via weak reference.
5.47 *
5.48 @@ -137,17 +146,17 @@
5.49
5.50 private static abstract class AImpl<M> extends PropertyBinding {
5.51 public final String name;
5.52 - public final boolean readOnly;
5.53 + public final byte propertyType;
5.54 final Proto.Type<M> access;
5.55 final Bindings<?> bindings;
5.56 final int index;
5.57
5.58 - public AImpl(Bindings<?> bindings, String name, int index, Proto.Type<M> access, boolean readOnly) {
5.59 + public AImpl(Bindings<?> bindings, String name, int index, Proto.Type<M> access, byte propertyType) {
5.60 this.bindings = bindings;
5.61 this.name = name;
5.62 this.index = index;
5.63 this.access = access;
5.64 - this.readOnly = readOnly;
5.65 + this.propertyType = propertyType;
5.66 }
5.67
5.68 protected abstract M model();
5.69 @@ -174,7 +183,12 @@
5.70
5.71 @Override
5.72 public boolean isReadOnly() {
5.73 - return readOnly;
5.74 + return (propertyType & 1) != 0;
5.75 + }
5.76 +
5.77 + @Override
5.78 + public boolean isConstant() {
5.79 + return (propertyType & 2) != 0;
5.80 }
5.81
5.82 @Override
5.83 @@ -186,8 +200,8 @@
5.84 private static final class Impl<M> extends AImpl<M> {
5.85 private final M model;
5.86
5.87 - public Impl(M model, Bindings<?> bindings, String name, int index, Proto.Type<M> access, boolean readOnly) {
5.88 - super(bindings, name, index, access, readOnly);
5.89 + public Impl(M model, Bindings<?> bindings, String name, int index, Proto.Type<M> access, byte propertyType) {
5.90 + super(bindings, name, index, access, propertyType);
5.91 this.model = model;
5.92 }
5.93
5.94 @@ -198,14 +212,14 @@
5.95
5.96 @Override
5.97 public PropertyBinding weak() {
5.98 - return new Weak(model, bindings, name, index, access, readOnly);
5.99 + return new Weak(model, bindings, name, index, access, propertyType);
5.100 }
5.101 }
5.102
5.103 private static final class Weak<M> extends AImpl<M> {
5.104 private final Reference<M> ref;
5.105 - public Weak(M model, Bindings<?> bindings, String name, int index, Proto.Type<M> access, boolean readOnly) {
5.106 - super(bindings, name, index, access, readOnly);
5.107 + public Weak(M model, Bindings<?> bindings, String name, int index, Proto.Type<M> access, byte propertyType) {
5.108 + super(bindings, name, index, access, propertyType);
5.109 this.ref = new WeakReference<M>(model);
5.110 }
5.111
6.1 --- a/json/src/main/java/org/netbeans/html/json/spi/Proto.java Mon Feb 22 06:09:33 2016 +0100
6.2 +++ b/json/src/main/java/org/netbeans/html/json/spi/Proto.java Mon Feb 22 19:58:32 2016 +0100
6.3 @@ -512,7 +512,7 @@
6.4 PropertyBinding[] pb = new PropertyBinding[type.propertyNames.length];
6.5 for (int i = 0; i < pb.length; i++) {
6.6 pb[i] = b.registerProperty(
6.7 - type.propertyNames[i], i, obj, type, type.propertyReadOnly[i]
6.8 + type.propertyNames[i], i, obj, type, type.propertyType[i]
6.9 );
6.10 }
6.11 FunctionBinding[] fb = new FunctionBinding[type.functions.length];
6.12 @@ -551,7 +551,7 @@
6.13 public static abstract class Type<Model> {
6.14 private final Class<Model> clazz;
6.15 private final String[] propertyNames;
6.16 - private final boolean[] propertyReadOnly;
6.17 + private final byte[] propertyType;
6.18 private final String[] functions;
6.19
6.20 /** Constructor for subclasses generated by the annotation processor
6.21 @@ -573,7 +573,7 @@
6.22 }
6.23 this.clazz = clazz;
6.24 this.propertyNames = new String[properties];
6.25 - this.propertyReadOnly = new boolean[properties];
6.26 + this.propertyType = new byte[properties];
6.27 this.functions = new String[functions];
6.28 JSON.register(clazz, this);
6.29 }
6.30 @@ -588,7 +588,29 @@
6.31 protected final void registerProperty(String name, int index, boolean readOnly) {
6.32 assert propertyNames[index] == null;
6.33 propertyNames[index] = name;
6.34 - propertyReadOnly[index] = readOnly;
6.35 + propertyType[index] = (byte) (readOnly ? 1 : 0);
6.36 + }
6.37 +
6.38 + /** Registers property for the type. It is expected each index
6.39 + * is initialized only once. The difference between <code>readOnly</code>
6.40 + * and <code>constant</code> is: The <code>constant</code> value is
6.41 + * assigned only at the beginning and never changed then - like the
6.42 + * {@link Property#mutable() non-mutable} property. On the other
6.43 + * hand, a <code>readOnly</code> property can change its value,
6.44 + * but not via a setter - just like {@link ComputedProperty}.
6.45 + *
6.46 + * @param name name of the property
6.47 + * @param index index of the property
6.48 + * @param readOnly is the property read only?
6.49 + * @param constant is the property assigned once and never changed again?
6.50 + * @since 1.3
6.51 + */
6.52 + protected final void registerProperty(
6.53 + String name, int index, boolean readOnly, boolean constant
6.54 + ) {
6.55 + assert propertyNames[index] == null;
6.56 + propertyNames[index] = name;
6.57 + propertyType[index] = (byte) ((readOnly ? 1 : 0) | (constant ? 2 : 0));
6.58 }
6.59
6.60 /** Registers function of given name at given index.
7.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java Mon Feb 22 06:09:33 2016 +0100
7.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java Mon Feb 22 19:58:32 2016 +0100
7.3 @@ -72,10 +72,12 @@
7.4 final Object createKO(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr, Knockout[] ko) {
7.5 String[] propNames = new String[propArr.length];
7.6 Boolean[] propReadOnly = new Boolean[propArr.length];
7.7 + Boolean[] propConstant = new Boolean[propArr.length];
7.8 Object[] propValues = new Object[propArr.length];
7.9 for (int i = 0; i < propNames.length; i++) {
7.10 propNames[i] = propArr[i].getPropertyName();
7.11 propReadOnly[i] = propArr[i].isReadOnly();
7.12 + propConstant[i] = propArr[i].isConstant();
7.13 Object value = propArr[i].getValue();
7.14 if (value instanceof Enum) {
7.15 value = value.toString();
7.16 @@ -93,7 +95,7 @@
7.17 }
7.18 newKO.wrapModel(
7.19 ret, copyFrom,
7.20 - propNames, propReadOnly, propValues,
7.21 + propNames, propReadOnly, propConstant, propValues,
7.22 funcNames
7.23 );
7.24 return ret;
8.1 --- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java Mon Feb 22 06:09:33 2016 +0100
8.2 +++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java Mon Feb 22 19:58:32 2016 +0100
8.3 @@ -168,7 +168,7 @@
8.4 javacall = true,
8.5 keepAlive = false,
8.6 wait4js = false,
8.7 - args = { "ret", "copyFrom", "propNames", "propReadOnly", "propValues", "funcNames" },
8.8 + args = { "ret", "copyFrom", "propNames", "propReadOnly", "propConstant", "propValues", "funcNames" },
8.9 body =
8.10 "Object.defineProperty(ret, 'ko4j', { value : this });\n"
8.11 + "function koComputed(index, name, readOnly, value) {\n"
8.12 @@ -225,7 +225,11 @@
8.13 + " ret[name] = cmpt;\n"
8.14 + "}\n"
8.15 + "for (var i = 0; i < propNames.length; i++) {\n"
8.16 - + " koComputed(i, propNames[i], propReadOnly[i], propValues[i]);\n"
8.17 + + " if (propConstant[i]) {\n"
8.18 + + " ret[propNames[i]] = propValues[i];\n"
8.19 + + " } else {\n"
8.20 + + " koComputed(i, propNames[i], propReadOnly[i], propValues[i]);\n"
8.21 + + " }\n"
8.22 + "}\n"
8.23 + "function koExpose(index, name) {\n"
8.24 + " ret[name] = function(data, ev) {\n"
8.25 @@ -240,7 +244,8 @@
8.26 )
8.27 native void wrapModel(
8.28 Object ret, Object copyFrom,
8.29 - String[] propNames, Boolean[] propReadOnly, Object propValues,
8.30 + String[] propNames, Boolean[] propReadOnly, Boolean[] propConstant,
8.31 + Object propValues,
8.32 String[] funcNames
8.33 );
8.34