@qooxdoo/framework 8.0.0-beta.2 → 8.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/Manifest.json +1 -1
  3. package/lib/compiler/compile-info.json +42 -43
  4. package/lib/compiler/index.js +555 -645
  5. package/package.json +1 -1
  6. package/source/class/qx/Class.js +23 -4
  7. package/source/class/qx/Mixin.js +15 -6
  8. package/source/class/qx/core/check/AbstractCheck.js +5 -1
  9. package/source/class/qx/core/check/CheckFactory.js +6 -0
  10. package/source/class/qx/core/check/DynamicTypeCheck.js +5 -0
  11. package/source/class/qx/core/property/ExplicitPropertyStorage.js +7 -19
  12. package/source/class/qx/core/property/IPropertyStorage.js +2 -21
  13. package/source/class/qx/core/property/Property.js +96 -72
  14. package/source/class/qx/core/property/SimplePropertyStorage.js +2 -18
  15. package/source/class/qx/data/MBinding.js +1 -1
  16. package/source/class/qx/data/SingleValueBinding.js +58 -100
  17. package/source/class/qx/data/binding/AbstractSegment.js +15 -10
  18. package/source/class/qx/data/binding/PropNameSegment.js +34 -11
  19. package/source/class/qx/test/Mixin.js +219 -0
  20. package/source/class/qx/test/Promise.js +10 -11
  21. package/source/class/qx/test/core/Property.js +22 -16
  22. package/source/class/qx/test/data/singlevalue/Async.js +17 -4
  23. package/source/class/qx/test/performance/Property.js +0 -1
  24. package/source/class/qx/test/ui/core/SingleSelectionManager.js +150 -0
  25. package/source/class/qx/tool/compiler/cli/api/CompilerApi.js +1 -2
  26. package/source/class/qx/ui/core/SingleSelectionManager.js +4 -4
  27. package/source/class/qx/ui/form/validation/Manager.js +1 -1
  28. package/source/resource/qx/decoration/Modern/table/boolean-false.png +0 -0
  29. package/source/resource/qx/decoration/Modern/table/boolean-true.png +0 -0
@@ -36,7 +36,7 @@ qx.Class.define("qx.test.core.Property", {
36
36
  extend: qx.core.Object
37
37
  });
38
38
 
39
- qx.Class.define("qx.test.cpnfv8.Superclass", {//cbh
39
+ qx.Class.define("qx.test.cpnfv8.Superclass", {
40
40
  extend: qx.test.cpnfv8.Object,
41
41
 
42
42
  construct(bRunning = true) {
@@ -170,11 +170,6 @@ qx.Class.define("qx.test.core.Property", {
170
170
  qx.test.cpnfv8.ExternalStorage._subclassStorage[property.getPropertyName()] = value;
171
171
  },
172
172
 
173
- /**@override */
174
- isAsyncStorage() {
175
- return false;
176
- },
177
-
178
173
  /**@override */
179
174
  get(thisObj, prop) {
180
175
  console.log("in externallyStored getter");
@@ -187,6 +182,11 @@ qx.Class.define("qx.test.core.Property", {
187
182
  qx.test.cpnfv8.ExternalStorage._subclassStorage[property.getPropertyName()] = value;
188
183
  },
189
184
 
185
+ /**@override */
186
+ supportsGetAsync() {
187
+ return false;
188
+ },
189
+
190
190
  /**@override */
191
191
  dereference(prop, property) {}
192
192
  },
@@ -235,7 +235,6 @@ qx.Class.define("qx.test.core.Property", {
235
235
  },
236
236
  delay: {
237
237
  init: 0,
238
- async: true,
239
238
  getAsync: async (prop, self) => {
240
239
  let p;
241
240
  p = new qx.Promise((resolve, reject) => {
@@ -1700,7 +1699,6 @@ qx.Class.define("qx.test.core.Property", {
1700
1699
  propTwo: {
1701
1700
  init: null,
1702
1701
  nullable: true,
1703
- async: true,
1704
1702
  apply: "_applyPropTwo",
1705
1703
  event: "changePropTwo"
1706
1704
  }
@@ -2323,7 +2321,6 @@ qx.Class.define("qx.test.core.Property", {
2323
2321
  extend: qx.core.Object,
2324
2322
  properties: {
2325
2323
  foo: {
2326
- async: true,
2327
2324
  init: 7,
2328
2325
  apply: function (value, old) {
2329
2326
  return new qx.Promise((resolve, reject) => {
@@ -2353,27 +2350,36 @@ qx.Class.define("qx.test.core.Property", {
2353
2350
 
2354
2351
  /**
2355
2352
  * Ensures that an error is thrown when trying to get an async property synchronously
2356
- * when the property is not ready yet, even if it has an init value.
2353
+ * when the property is not ready yet.
2357
2354
  */
2358
2355
  testGetSyncWhenNotReady() {
2359
2356
  qx.Class.undefine("qx.test.cpnfv8.GetSyncTest");
2357
+
2358
+ let fooCached = undefined;
2360
2359
  var Clazz = qx.Class.define("qx.test.cpnfv8.GetSyncTest", {
2361
2360
  extend: qx.core.Object,
2362
2361
  properties: {
2363
2362
  foo: {
2364
- async: true,
2365
- init: 7
2363
+ get() {
2364
+ return fooCached;
2365
+ },
2366
+ getAsync() {
2367
+ if (fooCached === undefined) {
2368
+ fooCached = 7;
2369
+ }
2370
+ return fooCached;
2371
+ },
2372
+ set(value) {
2373
+ fooCached = value;
2374
+ }
2366
2375
  }
2367
2376
  }
2368
2377
  });
2369
2378
 
2370
2379
  const doit = async () => {
2371
2380
  let instance = new Clazz();
2372
- //The property storage will be set to the init value during construction,
2373
- //so we must reset it manually.
2374
- delete instance.$$propertyValues.foo;
2375
2381
  let prop = qx.Class.getByProperty(Clazz, "foo");
2376
- this.assertFalse(prop.isInitialized(instance), "Property foo should not be initialized");
2382
+ this.assertFalse(prop.hasLocalValue(instance), "Property foo should not be locally defined");
2377
2383
  this.assertUndefined(instance.getSafe("foo"));
2378
2384
  try {
2379
2385
  instance.getFoo();
@@ -30,6 +30,19 @@ qx.Class.define("qx.test.data.singlevalue.Async", {
30
30
  __b2: null,
31
31
 
32
32
  setUp() {
33
+ qx.Bootstrap.undefine("qx.test.data.singlevalue.async.AsyncPropertyStorage");
34
+ qx.Bootstrap.define("qx.test.data.singlevalue.async.AsyncPropertyStorage", {
35
+ extend: qx.core.property.SimplePropertyStorage,
36
+ members: {
37
+ /**
38
+ * @Override
39
+ */
40
+ supportsGetAsync() {
41
+ return true;
42
+ }
43
+ }
44
+ });
45
+
33
46
  qx.Class.undefine("qx.test.data.singlevalue.async.Test");
34
47
  const Clazz = qx.Class.define("qx.test.data.singlevalue.async.Test", {
35
48
  extend: qx.core.Object,
@@ -38,17 +51,17 @@ qx.Class.define("qx.test.data.singlevalue.Async", {
38
51
  * The async input
39
52
  */
40
53
  ai: {
41
- async: true,
42
54
  nullable: true,
43
- init: null
55
+ init: null,
56
+ storage: qx.test.data.singlevalue.async.AsyncPropertyStorage
44
57
  },
45
58
  /**
46
59
  * The async output
47
60
  */
48
61
  ao: {
49
- async: true,
50
62
  nullable: true,
51
- init: null
63
+ init: null,
64
+ storage: qx.test.data.singlevalue.async.AsyncPropertyStorage
52
65
  },
53
66
  /**
54
67
  * Syncronous input
@@ -50,7 +50,6 @@ qx.Class.define("qx.test.performance.Property", {
50
50
  nullable: true,
51
51
  check: "String",
52
52
  event: "changeAlpha",
53
- async: true,
54
53
  apply: () => {}
55
54
  }
56
55
  }
@@ -0,0 +1,150 @@
1
+ /* ************************************************************************
2
+
3
+ qooxdoo - the new era of web development
4
+
5
+ http://qooxdoo.org
6
+
7
+ Copyright:
8
+ 2025 Qooxdoo contributors
9
+
10
+ License:
11
+ MIT: https://opensource.org/licenses/MIT
12
+ See the LICENSE file in the project's top-level directory for details.
13
+
14
+ ************************************************************************ */
15
+
16
+ /**
17
+ * Minimal ISingleSelectionProvider implementation for unit testing.
18
+ *
19
+ * @internal
20
+ * @ignore(qx.test.ui.core.MockSingleSelectionProvider)
21
+ */
22
+ qx.Class.define("qx.test.ui.core.MockSingleSelectionProvider", {
23
+ extend: qx.core.Object,
24
+ implement: [qx.ui.core.ISingleSelectionProvider],
25
+
26
+ construct(items) {
27
+ super();
28
+ this._items = items;
29
+ },
30
+
31
+ members: {
32
+ _items: null,
33
+
34
+ getItems() {
35
+ return this._items || [];
36
+ },
37
+
38
+ isItemSelectable(item) {
39
+ return true;
40
+ }
41
+ }
42
+ });
43
+
44
+ /**
45
+ * Tests for qx.ui.core.SingleSelectionManager
46
+ */
47
+ qx.Class.define("qx.test.ui.core.SingleSelectionManager", {
48
+ extend: qx.dev.unit.TestCase,
49
+
50
+ members: {
51
+ __manager: null,
52
+ __provider: null,
53
+ __items: null,
54
+
55
+ setUp() {
56
+ this.__items = [new qx.core.Object(), new qx.core.Object(), new qx.core.Object()];
57
+ this.__provider = new qx.test.ui.core.MockSingleSelectionProvider(this.__items);
58
+ this.__manager = new qx.ui.core.SingleSelectionManager(this.__provider);
59
+ },
60
+
61
+ tearDown() {
62
+ this.__manager.dispose();
63
+ this.__provider.dispose();
64
+ for (var item of this.__items) {
65
+ item.dispose();
66
+ }
67
+ this.__items = null;
68
+ },
69
+
70
+ /**
71
+ * Regression test for the fix: resetSelected() with allowEmptySelection=false
72
+ * must NOT fire changeSelected when the first item is already selected.
73
+ */
74
+ testNoSpuriousEventWhenResetSelectedWithFirstItemAlreadySelected() {
75
+ this.__manager.setAllowEmptySelection(false);
76
+ this.__manager.resetSelected();
77
+ this.assertIdentical(this.__items[0], this.__manager.getSelected(), "item[0] should be auto-selected");
78
+
79
+ var eventCount = 0;
80
+ this.__manager.addListener("changeSelected", function () {
81
+ eventCount++;
82
+ });
83
+
84
+ this.__manager.resetSelected();
85
+
86
+ this.assertEquals(0, eventCount, "changeSelected must not fire when selection is unchanged");
87
+ this.assertIdentical(this.__items[0], this.__manager.getSelected(), "Selection must still be item[0]");
88
+ },
89
+
90
+ /**
91
+ * resetSelected() when another item is selected must fire changeSelected
92
+ * and switch back to item[0].
93
+ */
94
+ testEventFiredWhenResetSelectedChangesSelection() {
95
+ this.__manager.setAllowEmptySelection(false);
96
+ this.__manager.setSelected(this.__items[1]);
97
+
98
+ var eventCount = 0;
99
+ var eventData = null;
100
+ this.__manager.addListener("changeSelected", function (e) {
101
+ eventCount++;
102
+ eventData = e.getData();
103
+ });
104
+
105
+ this.__manager.resetSelected();
106
+
107
+ this.assertEquals(1, eventCount, "changeSelected must fire when selection changes");
108
+ this.assertIdentical(this.__items[0], eventData, "Event data should be item[0]");
109
+ this.assertIdentical(this.__items[0], this.__manager.getSelected(), "item[0] should be selected after reset");
110
+ },
111
+
112
+ /**
113
+ * setSelected() with the already-selected item must not fire changeSelected
114
+ * (pre-existing early-exit guard).
115
+ */
116
+ testNoEventWhenSetSelectedWithSameItem() {
117
+ this.__manager.setSelected(this.__items[0]);
118
+
119
+ var eventCount = 0;
120
+ this.__manager.addListener("changeSelected", function () {
121
+ eventCount++;
122
+ });
123
+
124
+ this.__manager.setSelected(this.__items[0]);
125
+
126
+ this.assertEquals(0, eventCount, "changeSelected must not fire when setting the same item");
127
+ },
128
+
129
+ /**
130
+ * Switching allowEmptySelection from true to false on an empty manager
131
+ * must auto-select item[0] and fire changeSelected exactly once.
132
+ */
133
+ testAllowEmptySelectionFalseTriggersAutoSelect() {
134
+ this.assertTrue(this.__manager.isSelectionEmpty(), "Selection should be empty initially");
135
+
136
+ var eventCount = 0;
137
+ var eventData = null;
138
+ this.__manager.addListener("changeSelected", function (e) {
139
+ eventCount++;
140
+ eventData = e.getData();
141
+ });
142
+
143
+ this.__manager.setAllowEmptySelection(false);
144
+
145
+ this.assertEquals(1, eventCount, "changeSelected must fire when auto-selecting the first item");
146
+ this.assertIdentical(this.__items[0], eventData, "Event data should be item[0]");
147
+ this.assertIdentical(this.__items[0], this.__manager.getSelected(), "item[0] should be auto-selected");
148
+ }
149
+ }
150
+ });
@@ -51,8 +51,7 @@ qx.Class.define("qx.tool.compiler.cli.api.CompilerApi", {
51
51
  init: null,
52
52
  nullable: true,
53
53
  check: "qx.tool.compiler.cli.Command",
54
- event: "changeCommand",
55
- async: true
54
+ event: "changeCommand"
56
55
  }
57
56
  },
58
57
 
@@ -226,10 +226,6 @@ qx.Class.define("qx.ui.core.SingleSelectionManager", {
226
226
  var oldSelected = this.__selected;
227
227
  var newSelected = item;
228
228
 
229
- if (newSelected != null && oldSelected === newSelected) {
230
- return;
231
- }
232
-
233
229
  if (!this.isAllowEmptySelection() && newSelected == null) {
234
230
  var firstElement = this.getSelectables(true)[0];
235
231
 
@@ -238,6 +234,10 @@ qx.Class.define("qx.ui.core.SingleSelectionManager", {
238
234
  }
239
235
  }
240
236
 
237
+ if (newSelected !== null && newSelected === oldSelected) {
238
+ return;
239
+ }
240
+
241
241
  this.__selected = newSelected;
242
242
  this.fireDataEvent("changeSelected", newSelected, oldSelected);
243
243
  },
@@ -488,7 +488,7 @@ qx.Class.define("qx.ui.form.validation.Manager", {
488
488
 
489
489
  let msg = item.getInvalidMessage();
490
490
  if (
491
- msg &&
491
+ !msg &&
492
492
  qx.core.Environment.get(
493
493
  "qx.ui.form.validation.Manager.allowDefaultInvalidMessage"
494
494
  )