@qooxdoo/framework 7.0.0-beta.1 → 7.0.0-beta.5
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 +2 -2
- package/bin/deploy/qx +0 -0
- package/lib/compiler/compile-info.json +59 -60
- package/lib/compiler/index.js +636 -7815
- package/lib/resource/qx/tool/cli/templates/loader/loader-node.tmpl.js +3 -1
- package/lib/resource/qx/tool/cli/templates/skeleton/mobile/source/theme/custom/css/custom.css +1 -1
- package/lib/resource/qx/tool/cli/templates/skeleton/mobile/source/theme/custom/css/custom.css.map +1 -1
- package/lib/resource/qx/tool/cli/templates/template_vars.js +1 -1
- package/lib/resource/qx/tool/loadsass.js +2 -10
- package/lib/resource/qx/tool/schema/Manifest-1-0-0.json +1 -2
- package/lib/resource/qx/tool/schema/Manifest-2-0-0.json +1 -2
- package/lib/resource/qx/tool/schema/compile-1-0-0.json +3 -7
- package/package.json +11 -11
- package/source/class/qx/test/type/BaseString.js +7 -0
- package/source/class/qx/test/ui/embed/Iframe.js +1 -0
- package/source/class/qx/test/ui/form/ComboBox.js +0 -42
- package/source/class/qx/theme/manager/Decoration.js +0 -0
- package/source/class/qx/theme/tangible/ColorDark.js +0 -0
- package/source/class/qx/tool/cli/Cli.js +5 -3
- package/source/class/qx/tool/cli/api/CompilerApi.js +15 -5
- package/source/class/qx/tool/cli/commands/Command.js +7 -0
- package/source/class/qx/tool/cli/commands/Compile.js +6 -6
- package/source/class/qx/tool/cli/commands/Lint.js +30 -11
- package/source/class/qx/tool/cli/commands/Package.js +1 -2
- package/source/class/qx/tool/cli/commands/package/Publish.js +19 -10
- package/source/class/qx/tool/compiler/Analyser.js +21 -22
- package/source/class/qx/tool/compiler/app/WebFont.js +1 -1
- package/source/class/qx/tool/compiler/makers/AppMaker.js +13 -13
- package/source/class/qx/tool/compiler/targets/TypeScriptWriter.js +1 -2
- package/source/class/qx/tool/compiler/targets/meta/PolyfillJs.js +7 -7
- package/source/class/qx/tool/config/Abstract.js +3 -3
- package/source/class/qx/tool/config/Utils.js +10 -1
- package/source/class/qx/tool/utils/Json.js +1 -1
- package/source/class/qx/type/BaseString.js +2 -1
- package/source/class/qx/ui/container/SlideBar.js +3 -0
- package/source/class/qx/ui/core/Widget.js +70 -0
- package/source/class/qx/ui/core/scroll/NativeScrollBar.js +3 -0
- package/source/class/qx/ui/core/scroll/ScrollBar.js +3 -0
- package/source/class/qx/ui/form/AbstractSelectBox.js +38 -6
- package/source/class/qx/ui/form/Button.js +3 -0
- package/source/class/qx/ui/form/CheckBox.js +25 -1
- package/source/class/qx/ui/form/ComboBox.js +36 -27
- package/source/class/qx/ui/form/DateField.js +16 -1
- package/source/class/qx/ui/form/List.js +3 -0
- package/source/class/qx/ui/form/MenuButton.js +24 -2
- package/source/class/qx/ui/form/RadioButton.js +7 -0
- package/source/class/qx/ui/form/RadioButtonGroup.js +3 -0
- package/source/class/qx/ui/form/RadioGroup.js +19 -0
- package/source/class/qx/ui/form/SelectBox.js +23 -1
- package/source/class/qx/ui/form/Slider.js +15 -0
- package/source/class/qx/ui/form/SplitButton.js +3 -0
- package/source/class/qx/ui/form/ToggleButton.js +8 -0
- package/source/class/qx/ui/menu/AbstractButton.js +24 -0
- package/source/class/qx/ui/menu/Button.js +3 -0
- package/source/class/qx/ui/menu/CheckBox.js +8 -0
- package/source/class/qx/ui/menu/Manager.js +2 -0
- package/source/class/qx/ui/menu/Menu.js +63 -1
- package/source/class/qx/ui/menu/RadioButton.js +10 -1
- package/source/class/qx/ui/menubar/Button.js +0 -27
- package/source/class/qx/ui/menubar/MenuBar.js +12 -0
- package/source/class/qx/ui/splitpane/Blocker.js +3 -0
- package/source/class/qx/ui/splitpane/Pane.js +3 -0
- package/source/class/qx/ui/table/Table.js +24 -2
- package/source/class/qx/ui/table/cellrenderer/Abstract.js +3 -1
- package/source/class/qx/ui/table/cellrenderer/AbstractImage.js +7 -3
- package/source/class/qx/ui/table/headerrenderer/HeaderCell.js +3 -0
- package/source/class/qx/ui/table/pane/Header.js +3 -0
- package/source/class/qx/ui/table/pane/Scroller.js +3 -7
- package/source/class/qx/ui/table/rowrenderer/Default.js +1 -1
- package/source/class/qx/ui/tabview/Page.js +26 -0
- package/source/class/qx/ui/tabview/TabView.js +3 -0
- package/source/class/qx/ui/toolbar/Button.js +2 -27
- package/source/class/qx/ui/toolbar/CheckBox.js +0 -27
- package/source/class/qx/ui/toolbar/RadioButton.js +21 -0
- package/source/class/qx/ui/toolbar/SplitButton.js +0 -28
- package/source/class/qx/ui/toolbar/ToolBar.js +3 -0
- package/source/class/qx/ui/window/Window.js +8 -0
- package/source/class/qxWeb.js +2 -0
- package/source/resource/qx/decoration/Indigo/font/JosefinSlab-SemiBold.ttf +0 -0
- package/source/resource/qx/decoration/Indigo/font/SIL Open Font License 1.1.txt +0 -0
- package/source/resource/qx/iconfont/MaterialIcons/fetch-fonts.sh +0 -0
- package/source/resource/qx/mobile/scss/common/_gradients.scss +3 -1
- package/source/resource/qx/mobile/scss/theme/indigo/_styles.scss +1 -1
- package/source/resource/qx/mobile/scss/ui/_carousel.scss +2 -2
- package/source/resource/qx/mobile/scss/ui/_checkbox.scss +3 -3
- package/source/resource/qx/mobile/scss/ui/_collapsible.scss +2 -2
- package/source/resource/qx/mobile/scss/ui/_picker.scss +4 -4
- package/source/resource/qx/mobile/scss/ui/_radiobutton.scss +4 -4
- package/source/resource/qx/mobile/scss/ui/_slider.scss +7 -7
- package/source/resource/qx/scss/_gradients.scss +3 -1
- package/source/resource/qx/scss/_mixins.scss +4 -2
- package/source/resource/qx/tool/bin/build-devtools +0 -0
- package/source/resource/qx/tool/bin/build-website +0 -0
- package/source/resource/qx/tool/bin/download-assets +0 -0
- package/source/resource/qx/tool/cli/templates/loader/loader-node.tmpl.js +3 -1
- package/source/resource/qx/tool/cli/templates/skeleton/mobile/source/theme/custom/scss/_styles.scss +1 -1
- package/source/resource/qx/tool/cli/templates/template_vars.js +1 -1
- package/source/resource/qx/tool/loadsass.js +2 -10
- package/source/resource/qx/tool/schema/Manifest-1-0-0.json +1 -2
- package/source/resource/qx/tool/schema/Manifest-2-0-0.json +1 -2
- package/source/resource/qx/tool/schema/compile-1-0-0.json +3 -7
- package/source/resource/qx/website/scss/ui/_carousel.scss +2 -2
- package/lib/resource/qx/tool/website/.gitignore +0 -2
- package/source/class/qx/io/request/auth/.gitignore +0 -0
- package/source/class/qx/test/bom/client/.gitignore +0 -0
- package/source/class/qx/test/ui/control/.gitignore +0 -0
- package/source/class/qx/tool/compiler/Version.js +0 -20
- package/source/resource/qx/decoration/Modern/treevirtual/.gitignore +0 -0
- package/source/resource/qx/mobile/css/.gitignore +0 -3
- package/source/resource/qx/tool/website/.gitignore +0 -2
- package/source/resource/qx/website/.gitignore +0 -1
- package/source/resource/qx/website/scss/.gitignore +0 -1
|
@@ -332,7 +332,7 @@ qx.Class.define("qx.tool.config.Abstract", {
|
|
|
332
332
|
*/
|
|
333
333
|
setValue(prop_path, value, options) {
|
|
334
334
|
let originalValue = this.getValue(prop_path, options);
|
|
335
|
-
set_value(this.getData(), prop_path, value,
|
|
335
|
+
set_value(this.getData(), prop_path, value, {preservePaths:false});
|
|
336
336
|
try {
|
|
337
337
|
this.validate();
|
|
338
338
|
} catch (e) {
|
|
@@ -340,7 +340,7 @@ qx.Class.define("qx.tool.config.Abstract", {
|
|
|
340
340
|
if (originalValue === undefined) {
|
|
341
341
|
unset_value(this.getData(), prop_path);
|
|
342
342
|
} else {
|
|
343
|
-
set_value(this.getData(), prop_path, originalValue,
|
|
343
|
+
set_value(this.getData(), prop_path, originalValue, {preservePaths:false});
|
|
344
344
|
}
|
|
345
345
|
// throw
|
|
346
346
|
throw e;
|
|
@@ -362,7 +362,7 @@ qx.Class.define("qx.tool.config.Abstract", {
|
|
|
362
362
|
this.validate();
|
|
363
363
|
} catch (e) {
|
|
364
364
|
// revert value
|
|
365
|
-
set_value(this.getData(), prop_path, originalValue,
|
|
365
|
+
set_value(this.getData(), prop_path, originalValue, {preservePaths:false});
|
|
366
366
|
// throw
|
|
367
367
|
throw e;
|
|
368
368
|
}
|
|
@@ -191,7 +191,7 @@ qx.Class.define("qx.tool.config.Utils", {
|
|
|
191
191
|
|
|
192
192
|
throw new qx.tool.utils.Utils.UserError(`Path to the qx library cannot be determined.`);
|
|
193
193
|
};
|
|
194
|
-
|
|
194
|
+
|
|
195
195
|
this.__qxPathPromise = getQxPathImpl();
|
|
196
196
|
return await this.__qxPathPromise;
|
|
197
197
|
},
|
|
@@ -217,6 +217,15 @@ qx.Class.define("qx.tool.config.Utils", {
|
|
|
217
217
|
return qx.tool.config.Utils.getLibraryVersion(qxpath);
|
|
218
218
|
},
|
|
219
219
|
|
|
220
|
+
/**
|
|
221
|
+
* returns the compiler version.
|
|
222
|
+
* The version is written during compiler compile into the enviroment
|
|
223
|
+
* @return {String}
|
|
224
|
+
*/
|
|
225
|
+
getCompilerVersion() {
|
|
226
|
+
return qx.core.Environment.get("qx.compiler.version");
|
|
227
|
+
},
|
|
228
|
+
|
|
220
229
|
/**
|
|
221
230
|
* Returns the qooxdoo version used in the application in the current or given
|
|
222
231
|
* directory. Throws if no such version can be determined
|
|
@@ -272,6 +272,9 @@ qx.Class.define("qx.ui.container.SlideBar",
|
|
|
272
272
|
// property apply
|
|
273
273
|
_applyOrientation : function(value, old)
|
|
274
274
|
{
|
|
275
|
+
// ARIA attrs
|
|
276
|
+
this.getContentElement().setAttribute("aria-orientation", value);
|
|
277
|
+
|
|
275
278
|
var oldLayouts = [this.getLayout(), this._getLayout()];
|
|
276
279
|
var buttonForward = this.getChildControl("button-forward");
|
|
277
280
|
var buttonBackward = this.getChildControl("button-backward");
|
|
@@ -3827,6 +3827,76 @@ qx.Class.define("qx.ui.core.Widget",
|
|
|
3827
3827
|
|
|
3828
3828
|
|
|
3829
3829
|
|
|
3830
|
+
/*
|
|
3831
|
+
---------------------------------------------------------------------------
|
|
3832
|
+
ARIA attrs support
|
|
3833
|
+
---------------------------------------------------------------------------
|
|
3834
|
+
*/
|
|
3835
|
+
|
|
3836
|
+
/**
|
|
3837
|
+
* Sets the string which labels this widget. This will be read out by screenreaders. Needed if there is no
|
|
3838
|
+
* readable text/label in this widget which would automatically act as aria-label.
|
|
3839
|
+
* @param label {String} Labelling Text
|
|
3840
|
+
*/
|
|
3841
|
+
setAriaLabel: function(label) {
|
|
3842
|
+
this.getContentElement().setAttribute("aria-label", label);
|
|
3843
|
+
},
|
|
3844
|
+
|
|
3845
|
+
/**
|
|
3846
|
+
* Marks that this widget gets labelled by another widget. This will be read out by screenreaders as first
|
|
3847
|
+
* information.
|
|
3848
|
+
* Similiar to aria-label, difference being that the labelling widget is an different widget and multiple
|
|
3849
|
+
* widgets can be added.
|
|
3850
|
+
* @param labelWidgets {qx.ui.core.Widget[]} Indefinite Number of labelling Widgets
|
|
3851
|
+
*/
|
|
3852
|
+
addAriaLabelledBy: function(...labelWidgets) {
|
|
3853
|
+
this.__addAriaXBy(labelWidgets, "aria-labelledby");
|
|
3854
|
+
},
|
|
3855
|
+
|
|
3856
|
+
/**
|
|
3857
|
+
* Marks that this widget gets described by another widget. This will be read out by screenreaders as last
|
|
3858
|
+
* information. Multiple Widgets possible.
|
|
3859
|
+
* @param describingWidgets {qx.ui.core.Widget[]} Indefinite Number of describing Widgets
|
|
3860
|
+
*/
|
|
3861
|
+
addAriaDescribedBy: function(...describingWidgets) {
|
|
3862
|
+
this.__addAriaXBy(describingWidgets, "aria-describedby");
|
|
3863
|
+
},
|
|
3864
|
+
|
|
3865
|
+
/**
|
|
3866
|
+
* Sets either aria-labelledby or aria-describedby
|
|
3867
|
+
* @param widgets {qx.ui.core.Widget[]} Indefinite Number of widgets
|
|
3868
|
+
* @param ariaAttr {String} aria-labelledby | aria-describedby
|
|
3869
|
+
*/
|
|
3870
|
+
__addAriaXBy: function(widgets, ariaAttr) {
|
|
3871
|
+
if (!["aria-labelledby", "aria-describedby"].includes(ariaAttr)) {
|
|
3872
|
+
throw new Error("Only aria-labelledby or aria-describedby allowed!");
|
|
3873
|
+
}
|
|
3874
|
+
let idArr = [];
|
|
3875
|
+
for (const widget of widgets) {
|
|
3876
|
+
if (!(widget instanceof qx.ui.core.Widget)) {
|
|
3877
|
+
throw new Error("Given widget " + widget + " is not an instance of qx.ui.core.Widget!");
|
|
3878
|
+
}
|
|
3879
|
+
const contentEl = widget.getContentElement();
|
|
3880
|
+
let widgetId = contentEl.getAttribute("id");
|
|
3881
|
+
if (!widgetId) {
|
|
3882
|
+
widgetId = `label-${widget.toHashCode()}`;
|
|
3883
|
+
contentEl.setAttribute("id", widgetId);
|
|
3884
|
+
}
|
|
3885
|
+
if (!idArr.includes(widgetId)) {
|
|
3886
|
+
idArr.push(widgetId);
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
if (idArr.length === 0) {
|
|
3890
|
+
return;
|
|
3891
|
+
}
|
|
3892
|
+
const idStr = idArr.join(" ");
|
|
3893
|
+
const contentEl = this.getContentElement();
|
|
3894
|
+
let res = contentEl.getAttribute(ariaAttr);
|
|
3895
|
+
res = res ? `${res} ${idStr}` : idStr;
|
|
3896
|
+
contentEl.setAttribute(ariaAttr, res);
|
|
3897
|
+
},
|
|
3898
|
+
|
|
3899
|
+
|
|
3830
3900
|
|
|
3831
3901
|
/*
|
|
3832
3902
|
---------------------------------------------------------------------------
|
|
@@ -234,6 +234,9 @@ qx.Class.define("qx.ui.core.scroll.NativeScrollBar",
|
|
|
234
234
|
// property apply
|
|
235
235
|
_applyOrientation : function(value, old)
|
|
236
236
|
{
|
|
237
|
+
// ARIA attrs
|
|
238
|
+
this.getContentElement().setAttribute("aria-orientation", value);
|
|
239
|
+
|
|
237
240
|
var isHorizontal = this.__isHorizontal = value === "horizontal";
|
|
238
241
|
|
|
239
242
|
this.set({
|
|
@@ -301,6 +301,9 @@ qx.Class.define("qx.ui.core.scroll.ScrollBar",
|
|
|
301
301
|
// property apply
|
|
302
302
|
_applyOrientation : function(value, old)
|
|
303
303
|
{
|
|
304
|
+
// ARIA attrs
|
|
305
|
+
this.getContentElement().setAttribute("aria-orientation", value);
|
|
306
|
+
|
|
304
307
|
// Dispose old layout
|
|
305
308
|
var oldLayout = this._getLayout();
|
|
306
309
|
if (oldLayout) {
|
|
@@ -55,6 +55,12 @@ qx.Class.define("qx.ui.form.AbstractSelectBox",
|
|
|
55
55
|
this._setLayout(layout);
|
|
56
56
|
layout.setAlignY("middle");
|
|
57
57
|
|
|
58
|
+
// ARIA attrs
|
|
59
|
+
const contentEl = this.getContentElement();
|
|
60
|
+
contentEl.setAttribute("role", "button");
|
|
61
|
+
contentEl.setAttribute("aria-haspopup", "listbox");
|
|
62
|
+
contentEl.setAttribute("aria-expanded", false);
|
|
63
|
+
|
|
58
64
|
// Register listeners
|
|
59
65
|
this.addListener("keypress", this._onKeyPress);
|
|
60
66
|
this.addListener("blur", this._onBlur, this);
|
|
@@ -130,7 +136,7 @@ qx.Class.define("qx.ui.form.AbstractSelectBox",
|
|
|
130
136
|
|
|
131
137
|
switch(id)
|
|
132
138
|
{
|
|
133
|
-
case "list":
|
|
139
|
+
case "list": {
|
|
134
140
|
control = new qx.ui.form.List().set({
|
|
135
141
|
focusable: false,
|
|
136
142
|
keepFocus: true,
|
|
@@ -140,12 +146,18 @@ qx.Class.define("qx.ui.form.AbstractSelectBox",
|
|
|
140
146
|
selectionMode: "one",
|
|
141
147
|
quickSelection: true
|
|
142
148
|
});
|
|
149
|
+
const listId = "list-" + control.toHashCode();
|
|
150
|
+
const childrenContainerEl = control.getChildrenContainer().getContentElement();
|
|
151
|
+
childrenContainerEl.setAttribute("id", listId);
|
|
152
|
+
childrenContainerEl.setAttribute("role", "listbox");
|
|
153
|
+
this.getContentElement().setAttribute("aria-owns", listId);
|
|
143
154
|
|
|
155
|
+
control.addListener("addItem", this._onListAddItem, this);
|
|
144
156
|
control.addListener("changeSelection", this._onListChangeSelection, this);
|
|
145
157
|
control.addListener("pointerdown", this._onListPointerDown, this);
|
|
146
158
|
control.getChildControl("pane").addListener("tap", this.close, this);
|
|
147
159
|
break;
|
|
148
|
-
|
|
160
|
+
}
|
|
149
161
|
case "popup":
|
|
150
162
|
control = new qx.ui.popup.Popup(new qx.ui.layout.VBox());
|
|
151
163
|
control.setAutoHide(false);
|
|
@@ -292,8 +304,8 @@ qx.Class.define("qx.ui.form.AbstractSelectBox",
|
|
|
292
304
|
e.stopPropagation();
|
|
293
305
|
}
|
|
294
306
|
|
|
295
|
-
// hide the list always on escape
|
|
296
|
-
else if (!listPopup.isHidden() && identifier == "Escape")
|
|
307
|
+
// hide the list always on escape and tab
|
|
308
|
+
else if (!listPopup.isHidden() && (identifier == "Escape" || identifier == "Tab"))
|
|
297
309
|
{
|
|
298
310
|
this.close();
|
|
299
311
|
e.stop();
|
|
@@ -315,7 +327,23 @@ qx.Class.define("qx.ui.form.AbstractSelectBox",
|
|
|
315
327
|
_onResize : function(e){
|
|
316
328
|
this.getChildControl("popup").setMinWidth(e.getData().width);
|
|
317
329
|
},
|
|
318
|
-
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Sets ARIA attributes on the item
|
|
333
|
+
*
|
|
334
|
+
* @param e {qx.event.type.Data} Data Event
|
|
335
|
+
*/
|
|
336
|
+
_onListAddItem : function(e) {
|
|
337
|
+
const item = e.getData();
|
|
338
|
+
const contentEl = item.getContentElement();
|
|
339
|
+
contentEl.setAttribute("id", "list-item-" + item.toHashCode());
|
|
340
|
+
contentEl.setAttribute("role", "option");
|
|
341
|
+
const ariaSelected = contentEl.getAttribute("aria-selected");
|
|
342
|
+
// aria-selected may be already set from changeSelection listener
|
|
343
|
+
if (ariaSelected === null || ariaSelected === undefined) {
|
|
344
|
+
contentEl.setAttribute("aria-selected", false);
|
|
345
|
+
}
|
|
346
|
+
},
|
|
319
347
|
|
|
320
348
|
/**
|
|
321
349
|
* Syncs the own property from the list change
|
|
@@ -343,7 +371,11 @@ qx.Class.define("qx.ui.form.AbstractSelectBox",
|
|
|
343
371
|
* @param e {qx.event.type.Data} Property change event
|
|
344
372
|
*/
|
|
345
373
|
_onPopupChangeVisibility : function(e) {
|
|
346
|
-
e.getData() == "visible"
|
|
374
|
+
const visible = e.getData() == "visible";
|
|
375
|
+
visible ? this.addState("popupOpen") : this.removeState("popupOpen");
|
|
376
|
+
|
|
377
|
+
// ARIA attrs
|
|
378
|
+
this.getContentElement().setAttribute("aria-expanded", visible);
|
|
347
379
|
}
|
|
348
380
|
}
|
|
349
381
|
});
|
|
@@ -75,6 +75,9 @@ qx.Class.define("qx.ui.form.Button",
|
|
|
75
75
|
this.setCommand(command);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// ARIA attrs
|
|
79
|
+
this.getContentElement().setAttribute("role", "button");
|
|
80
|
+
|
|
78
81
|
// Add listeners
|
|
79
82
|
this.addListener("pointerover", this._onPointerOver);
|
|
80
83
|
this.addListener("pointerout", this._onPointerOut);
|
|
@@ -54,6 +54,12 @@ qx.Class.define("qx.ui.form.CheckBox",
|
|
|
54
54
|
// Initialize the checkbox to a valid value (the default is null which
|
|
55
55
|
// is invalid)
|
|
56
56
|
this.setValue(false);
|
|
57
|
+
|
|
58
|
+
// ARIA attrs
|
|
59
|
+
const contentEl = this.getContentElement();
|
|
60
|
+
contentEl.setAttribute("role", "checkbox");
|
|
61
|
+
contentEl.removeAttribute("aria-pressed");
|
|
62
|
+
contentEl.setAttribute("aria-checked", false);
|
|
57
63
|
},
|
|
58
64
|
|
|
59
65
|
|
|
@@ -107,6 +113,24 @@ qx.Class.define("qx.ui.form.CheckBox",
|
|
|
107
113
|
"toolTipText",
|
|
108
114
|
"value",
|
|
109
115
|
"menu"
|
|
110
|
-
]
|
|
116
|
+
],
|
|
117
|
+
|
|
118
|
+
// overridden
|
|
119
|
+
_applyValue : function(value, old) {
|
|
120
|
+
value ? this.addState("checked") : this.removeState("checked");
|
|
121
|
+
|
|
122
|
+
let ariaChecked = Boolean(value);
|
|
123
|
+
if (this.isTriState()) {
|
|
124
|
+
if (value === null) {
|
|
125
|
+
ariaChecked = "mixed";
|
|
126
|
+
this.addState("undetermined");
|
|
127
|
+
} else if (old === null) {
|
|
128
|
+
this.removeState("undetermined");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ARIA attrs
|
|
133
|
+
this.getContentElement().setAttribute("aria-checked", ariaChecked);
|
|
134
|
+
},
|
|
111
135
|
}
|
|
112
136
|
});
|
|
@@ -50,6 +50,9 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
50
50
|
var textField = this._createChildControl("textfield");
|
|
51
51
|
this._createChildControl("button");
|
|
52
52
|
|
|
53
|
+
// ARIA attrs
|
|
54
|
+
this.getContentElement().setAttribute("role", "combobox");
|
|
55
|
+
|
|
53
56
|
this.addListener("tap", this._onTap);
|
|
54
57
|
|
|
55
58
|
// forward the focusin and focusout events to the textfield. The textfield
|
|
@@ -242,26 +245,25 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
242
245
|
var popup = this.getChildControl("popup");
|
|
243
246
|
var iden = e.getKeyIdentifier();
|
|
244
247
|
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
this.toggle();
|
|
249
|
-
e.stopPropagation();
|
|
250
|
-
}
|
|
251
|
-
else if (iden == "Enter")
|
|
252
|
-
{
|
|
253
|
-
if (popup.isVisible())
|
|
254
|
-
{
|
|
248
|
+
if (popup.isVisible()) {
|
|
249
|
+
const listIdentifier = ["Up", "Down", "PageUp", "PageDown", "Escape", "Tab"];
|
|
250
|
+
if (iden == "Enter") {
|
|
255
251
|
this._setPreselectedItem();
|
|
256
252
|
this.resetAllTextSelection();
|
|
257
253
|
this.close();
|
|
258
254
|
e.stop();
|
|
255
|
+
} else if (listIdentifier.includes(iden)) {
|
|
256
|
+
this.base(arguments, e);
|
|
257
|
+
} else {
|
|
258
|
+
this.close();
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
if (iden == "Down") {
|
|
262
|
+
this.getChildControl("button").addState("selected");
|
|
263
|
+
this.open();
|
|
264
|
+
e.stop();
|
|
259
265
|
}
|
|
260
266
|
}
|
|
261
|
-
else if (popup.isVisible())
|
|
262
|
-
{
|
|
263
|
-
this.base(arguments, e);
|
|
264
|
-
}
|
|
265
267
|
},
|
|
266
268
|
|
|
267
269
|
|
|
@@ -333,6 +335,13 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
333
335
|
this.__preSelectedItem = null;
|
|
334
336
|
}
|
|
335
337
|
}
|
|
338
|
+
|
|
339
|
+
// Set aria-activedescendant
|
|
340
|
+
if (current && current[0]) {
|
|
341
|
+
this.getChildControl("textfield").getContentElement().setAttribute("aria-activedescendant", current[0].getContentElement().getAttribute("id"));
|
|
342
|
+
} else {
|
|
343
|
+
this.getChildControl("textfield").getContentElement().removeAttribute("aria-activedescendant");
|
|
344
|
+
}
|
|
336
345
|
},
|
|
337
346
|
|
|
338
347
|
|
|
@@ -363,16 +372,6 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
363
372
|
list.resetSelection();
|
|
364
373
|
}
|
|
365
374
|
}
|
|
366
|
-
else
|
|
367
|
-
{
|
|
368
|
-
// When closing the popup text should selected and field should
|
|
369
|
-
// have the focus. Identical to when reaching the field using the TAB key.
|
|
370
|
-
//
|
|
371
|
-
// Only focus if popup was visible before. Fixes [BUG #4453].
|
|
372
|
-
if (e.getOldData() == "visible") {
|
|
373
|
-
this.tabFocus();
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
375
|
|
|
377
376
|
// In all cases: Remove focused state from button
|
|
378
377
|
this.getChildControl("button").removeState("selected");
|
|
@@ -390,11 +389,12 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
390
389
|
var value = e.getData();
|
|
391
390
|
|
|
392
391
|
var list = this.getChildControl("list");
|
|
392
|
+
let current = null;
|
|
393
393
|
if (value != null) {
|
|
394
394
|
// Select item when possible
|
|
395
|
-
|
|
396
|
-
if (
|
|
397
|
-
list.setSelection([
|
|
395
|
+
current = list.findItem(value, false);
|
|
396
|
+
if (current) {
|
|
397
|
+
list.setSelection([current]);
|
|
398
398
|
} else {
|
|
399
399
|
list.resetSelection();
|
|
400
400
|
}
|
|
@@ -402,6 +402,15 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
402
402
|
list.resetSelection();
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
+
// ARIA attrs
|
|
406
|
+
const old = e.getOldData() ? list.findItem(e.getOldData(), false) : null;
|
|
407
|
+
if (old && old !== current) {
|
|
408
|
+
old.getContentElement().setAttribute("aria-selected", false);
|
|
409
|
+
}
|
|
410
|
+
if (current) {
|
|
411
|
+
current.getContentElement().setAttribute("aria-selected", true);
|
|
412
|
+
}
|
|
413
|
+
|
|
405
414
|
// Fire event
|
|
406
415
|
this.fireDataEvent("changeValue", value, e.getOldData());
|
|
407
416
|
},
|
|
@@ -602,7 +602,22 @@ qx.Class.define("qx.ui.form.DateField",
|
|
|
602
602
|
|
|
603
603
|
field.getFocusElement().focus();
|
|
604
604
|
field.selectAllText();
|
|
605
|
-
}
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
// overridden
|
|
608
|
+
setAriaLabel: function(label) {
|
|
609
|
+
this.getChildControl("textfield").setAriaLabel(label);
|
|
610
|
+
},
|
|
611
|
+
|
|
612
|
+
// overridden
|
|
613
|
+
addAriaLabelledBy: function(...labelWidgets) {
|
|
614
|
+
this.getChildControl("textfield").addAriaLabelledBy(...labelWidgets);
|
|
615
|
+
},
|
|
616
|
+
|
|
617
|
+
// overridden
|
|
618
|
+
addAriaDescribedBy: function(...describingWidgets) {
|
|
619
|
+
this.getChildControl("textfield").addAriaDescribedBy(...describingWidgets);
|
|
620
|
+
},
|
|
606
621
|
},
|
|
607
622
|
|
|
608
623
|
|
|
@@ -277,6 +277,9 @@ qx.Class.define("qx.ui.form.List",
|
|
|
277
277
|
// property apply
|
|
278
278
|
_applyOrientation : function(value, old)
|
|
279
279
|
{
|
|
280
|
+
// ARIA attrs
|
|
281
|
+
this.getContentElement().setAttribute("aria-orientation", value);
|
|
282
|
+
|
|
280
283
|
var content = this.__content;
|
|
281
284
|
|
|
282
285
|
// save old layout for disposal
|
|
@@ -45,6 +45,9 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
45
45
|
if (menu != null) {
|
|
46
46
|
this.setMenu(menu);
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
// ARIA attrs
|
|
50
|
+
this.getContentElement().setAttribute("role", "button");
|
|
48
51
|
},
|
|
49
52
|
|
|
50
53
|
|
|
@@ -112,6 +115,7 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
112
115
|
old.resetOpener();
|
|
113
116
|
}
|
|
114
117
|
|
|
118
|
+
const contentEl = this.getContentElement();
|
|
115
119
|
if (value)
|
|
116
120
|
{
|
|
117
121
|
value.addListener("changeVisibility", this._onMenuChange, this);
|
|
@@ -119,6 +123,16 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
119
123
|
|
|
120
124
|
value.removeState("submenu");
|
|
121
125
|
value.removeState("contextmenu");
|
|
126
|
+
|
|
127
|
+
// ARIA attrs
|
|
128
|
+
contentEl.setAttribute("aria-haspopup", "menu");
|
|
129
|
+
contentEl.setAttribute("aria-expanded", value.isVisible());
|
|
130
|
+
contentEl.setAttribute("aria-controls", value.getContentElement().getAttribute("id"));
|
|
131
|
+
} else {
|
|
132
|
+
// ARIA attrs
|
|
133
|
+
contentEl.removeAttribute("aria-haspopup");
|
|
134
|
+
contentEl.removeAttribute("aria-expanded");
|
|
135
|
+
contentEl.removeAttribute("aria-controls");
|
|
122
136
|
}
|
|
123
137
|
},
|
|
124
138
|
|
|
@@ -142,6 +156,10 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
142
156
|
|
|
143
157
|
if (menu)
|
|
144
158
|
{
|
|
159
|
+
// Focus this button when the menu opens
|
|
160
|
+
if (this.isFocusable() && !qx.ui.core.FocusHandler.getInstance().isFocused(this)) {
|
|
161
|
+
this.focus();
|
|
162
|
+
}
|
|
145
163
|
// Hide all menus first
|
|
146
164
|
qx.ui.menu.Manager.getInstance().hideAll();
|
|
147
165
|
|
|
@@ -177,12 +195,15 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
177
195
|
_onMenuChange : function(e)
|
|
178
196
|
{
|
|
179
197
|
var menu = this.getMenu();
|
|
180
|
-
|
|
181
|
-
if (
|
|
198
|
+
const menuVisible = menu.isVisible()
|
|
199
|
+
if (menuVisible) {
|
|
182
200
|
this.addState("pressed");
|
|
183
201
|
} else {
|
|
184
202
|
this.removeState("pressed");
|
|
185
203
|
}
|
|
204
|
+
|
|
205
|
+
// ARIA attrs
|
|
206
|
+
this.getContentElement().setAttribute("aria-expanded", menuVisible);
|
|
186
207
|
},
|
|
187
208
|
|
|
188
209
|
|
|
@@ -241,6 +262,7 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
241
262
|
{
|
|
242
263
|
switch(e.getKeyIdentifier())
|
|
243
264
|
{
|
|
265
|
+
case "Space":
|
|
244
266
|
case "Enter":
|
|
245
267
|
this.removeState("abandoned");
|
|
246
268
|
this.addState("pressed");
|
|
@@ -68,6 +68,12 @@ qx.Class.define("qx.ui.form.RadioButton",
|
|
|
68
68
|
|
|
69
69
|
this.base(arguments, label);
|
|
70
70
|
|
|
71
|
+
// ARIA attrs
|
|
72
|
+
// Important: (Grouped) radio btns should be children of a div with role 'radiogroup'
|
|
73
|
+
const contentEl = this.getContentElement();
|
|
74
|
+
contentEl.setAttribute("role", "radio");
|
|
75
|
+
contentEl.setAttribute("aria-checked", false);
|
|
76
|
+
|
|
71
77
|
// Add listeners
|
|
72
78
|
this.addListener("execute", this._onExecute);
|
|
73
79
|
this.addListener("keypress", this._onKeyPress);
|
|
@@ -164,6 +170,7 @@ qx.Class.define("qx.ui.form.RadioButton",
|
|
|
164
170
|
value ?
|
|
165
171
|
this.addState("checked") :
|
|
166
172
|
this.removeState("checked");
|
|
173
|
+
this.getContentElement().setAttribute("aria-checked", Boolean(value));
|
|
167
174
|
},
|
|
168
175
|
|
|
169
176
|
|
|
@@ -522,7 +522,26 @@ qx.Class.define("qx.ui.form.RadioGroup",
|
|
|
522
522
|
|
|
523
523
|
if (value) {
|
|
524
524
|
value.set(groupedProperty, true);
|
|
525
|
+
|
|
526
|
+
// If Group is focused, the selection was changed by keyboard. Switch focus to new value
|
|
527
|
+
if (this.__isGroupFocused() && value.isFocusable()) {
|
|
528
|
+
value.focus();
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Checks if this group is focused by checking focused state of each item
|
|
535
|
+
* @returns {Boolean} result
|
|
536
|
+
*/
|
|
537
|
+
__isGroupFocused: function () {
|
|
538
|
+
const focusHandler = qx.ui.core.FocusHandler.getInstance();
|
|
539
|
+
for (const item of this._getItems()) {
|
|
540
|
+
if (focusHandler.isFocused(item)) {
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
525
543
|
}
|
|
544
|
+
return false;
|
|
526
545
|
}
|
|
527
546
|
},
|
|
528
547
|
|
|
@@ -221,6 +221,16 @@ qx.Class.define("qx.ui.form.SelectBox",
|
|
|
221
221
|
|
|
222
222
|
this.__updateIcon();
|
|
223
223
|
this.__updateLabel();
|
|
224
|
+
|
|
225
|
+
// ARIA attrs
|
|
226
|
+
const old = e.getOldData() ? e.getOldData()[0] : null;
|
|
227
|
+
const current = this.getSelection()[0];
|
|
228
|
+
if (old && old !== current) {
|
|
229
|
+
old.getContentElement().setAttribute("aria-selected", false);
|
|
230
|
+
}
|
|
231
|
+
if (current) {
|
|
232
|
+
current.getContentElement().setAttribute("aria-selected", true);
|
|
233
|
+
}
|
|
224
234
|
},
|
|
225
235
|
|
|
226
236
|
|
|
@@ -327,7 +337,11 @@ qx.Class.define("qx.ui.form.SelectBox",
|
|
|
327
337
|
_onKeyPress : function(e)
|
|
328
338
|
{
|
|
329
339
|
var iden = e.getKeyIdentifier();
|
|
330
|
-
if(iden == "
|
|
340
|
+
if ((iden == "Down" || iden == "Up") && e.isAltPressed()) {
|
|
341
|
+
this.toggle();
|
|
342
|
+
e.stop();
|
|
343
|
+
}
|
|
344
|
+
else if (iden == "Enter" || iden == "Space")
|
|
331
345
|
{
|
|
332
346
|
// Apply pre-selected item (translate quick selection to real selection)
|
|
333
347
|
if (this.__preSelectedItem)
|
|
@@ -337,6 +351,7 @@ qx.Class.define("qx.ui.form.SelectBox",
|
|
|
337
351
|
}
|
|
338
352
|
|
|
339
353
|
this.toggle();
|
|
354
|
+
e.stop();
|
|
340
355
|
}
|
|
341
356
|
else
|
|
342
357
|
{
|
|
@@ -413,6 +428,13 @@ qx.Class.define("qx.ui.form.SelectBox",
|
|
|
413
428
|
{
|
|
414
429
|
this.resetSelection();
|
|
415
430
|
}
|
|
431
|
+
|
|
432
|
+
// Set aria-activedescendant
|
|
433
|
+
if (current && current[0]) {
|
|
434
|
+
this.getContentElement().setAttribute("aria-activedescendant", current[0].getContentElement().getAttribute("id"));
|
|
435
|
+
} else {
|
|
436
|
+
this.getContentElement().removeAttribute("aria-activedescendant");
|
|
437
|
+
}
|
|
416
438
|
},
|
|
417
439
|
|
|
418
440
|
// overridden
|