@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.
- package/CHANGELOG.md +9 -0
- package/Manifest.json +1 -1
- package/lib/compiler/compile-info.json +42 -43
- package/lib/compiler/index.js +555 -645
- package/package.json +1 -1
- package/source/class/qx/Class.js +23 -4
- package/source/class/qx/Mixin.js +15 -6
- package/source/class/qx/core/check/AbstractCheck.js +5 -1
- package/source/class/qx/core/check/CheckFactory.js +6 -0
- package/source/class/qx/core/check/DynamicTypeCheck.js +5 -0
- package/source/class/qx/core/property/ExplicitPropertyStorage.js +7 -19
- package/source/class/qx/core/property/IPropertyStorage.js +2 -21
- package/source/class/qx/core/property/Property.js +96 -72
- package/source/class/qx/core/property/SimplePropertyStorage.js +2 -18
- package/source/class/qx/data/MBinding.js +1 -1
- package/source/class/qx/data/SingleValueBinding.js +58 -100
- package/source/class/qx/data/binding/AbstractSegment.js +15 -10
- package/source/class/qx/data/binding/PropNameSegment.js +34 -11
- package/source/class/qx/test/Mixin.js +219 -0
- package/source/class/qx/test/Promise.js +10 -11
- package/source/class/qx/test/core/Property.js +22 -16
- package/source/class/qx/test/data/singlevalue/Async.js +17 -4
- package/source/class/qx/test/performance/Property.js +0 -1
- package/source/class/qx/test/ui/core/SingleSelectionManager.js +150 -0
- package/source/class/qx/tool/compiler/cli/api/CompilerApi.js +1 -2
- package/source/class/qx/ui/core/SingleSelectionManager.js +4 -4
- package/source/class/qx/ui/form/validation/Manager.js +1 -1
- package/source/resource/qx/decoration/Modern/table/boolean-false.png +0 -0
- 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", {
|
|
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
|
|
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
|
-
|
|
2365
|
-
|
|
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.
|
|
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
|
|
@@ -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
|
+
});
|
|
@@ -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
|
},
|
|
Binary file
|
|
Binary file
|