@qooxdoo/framework 7.0.0-beta.2 → 7.0.0-beta.6
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 +12 -0
- package/Manifest.json +2 -3
- package/README.md +7 -3
- package/bin/deploy/qx +0 -0
- package/lib/compiler/compile-info.json +44 -45
- package/lib/compiler/index.js +1971 -8371
- 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 +6 -12
- 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 +25 -12
- package/source/class/qx/io/__init__.js +5 -3
- package/source/class/qx/io/exception/Cancel.js +34 -0
- package/source/class/qx/io/exception/Exception.js +38 -0
- package/source/class/qx/{tool/compiler/Version.js → io/exception/Protocol.js} +13 -7
- package/source/class/qx/io/exception/Transport.js +39 -0
- package/source/class/qx/io/exception/__init__.js +4 -0
- package/source/class/qx/io/graphql/Client.js +112 -0
- package/source/class/qx/io/graphql/__init__.js +9 -0
- package/source/class/qx/io/graphql/protocol/Message.js +65 -0
- package/source/class/qx/io/graphql/protocol/Request.js +95 -0
- package/source/class/qx/io/graphql/protocol/Response.js +61 -0
- package/source/class/qx/io/graphql/protocol/__init__.js +6 -0
- package/source/class/qx/io/jsonrpc/Client.js +323 -0
- package/source/class/qx/io/jsonrpc/__init__.js +15 -0
- package/source/class/qx/io/jsonrpc/protocol/Batch.js +97 -0
- package/source/class/qx/io/jsonrpc/protocol/Error.js +63 -0
- package/source/class/qx/io/jsonrpc/protocol/Message.js +48 -0
- package/source/class/qx/io/jsonrpc/protocol/Notification.js +45 -0
- package/source/class/qx/io/jsonrpc/protocol/Parser.js +81 -0
- package/source/class/qx/io/jsonrpc/protocol/Request.js +93 -0
- package/source/class/qx/io/jsonrpc/protocol/Result.js +48 -0
- package/source/class/qx/io/jsonrpc/protocol/__init__.js +5 -0
- package/source/class/qx/io/request/authentication/Bearer.js +52 -0
- package/source/class/qx/io/transport/AbstractClient.js +100 -0
- package/source/class/qx/io/transport/AbstractTransport.js +41 -0
- package/source/class/qx/io/transport/Fetch.js +95 -0
- package/source/class/qx/io/transport/ITransport.js +40 -0
- package/source/class/qx/io/transport/PostMessage.js +55 -0
- package/source/class/qx/io/transport/Websocket.js +97 -0
- package/source/class/qx/io/transport/Xhr.js +139 -0
- package/source/class/qx/io/transport/__init__.js +18 -0
- package/source/class/qx/test/io/MAssert.js +46 -0
- package/source/class/qx/test/io/graphql/Client.js +169 -0
- package/source/class/qx/test/io/graphql/ClientFetch.js +34 -0
- package/source/class/qx/test/io/graphql/Request.js +42 -0
- package/source/class/qx/test/io/jsonrpc/Client.js +267 -0
- package/source/class/qx/test/io/jsonrpc/Protocol.js +80 -0
- package/source/class/qx/test/io/transport/PostMessage.js +56 -0
- package/source/class/qx/test/io/transport/Websocket.js +63 -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/test/util/DateFormat.js +45 -6
- 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 +4 -4
- 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 +33 -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 +15 -14
- package/source/class/qx/tool/compiler/targets/Target.js +2 -1
- package/source/class/qx/tool/compiler/targets/TypeScriptWriter.js +1 -2
- package/source/class/qx/tool/compiler/targets/meta/PolyfillJs.js +17 -9
- 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/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 +41 -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 +28 -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 +28 -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 +28 -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 +74 -2
- 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/Model.js +10 -4
- 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/qx/util/format/DateFormat.js +44 -17
- 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/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/template_vars.js +1 -1
- package/source/resource/qx/tool/loadsass.js +6 -12
- 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/translation/hr.po +297 -0
- 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/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
|
@@ -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,25 +245,24 @@ 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
|
-
}
|
|
261
|
-
else if (popup.isVisible())
|
|
262
|
-
{
|
|
263
|
-
this.base(arguments, e);
|
|
264
266
|
}
|
|
265
267
|
},
|
|
266
268
|
|
|
@@ -333,6 +335,18 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
333
335
|
this.__preSelectedItem = null;
|
|
334
336
|
}
|
|
335
337
|
}
|
|
338
|
+
|
|
339
|
+
// Set aria-activedescendant
|
|
340
|
+
const textFieldContentEl = this.getChildControl("textfield").getContentElement();
|
|
341
|
+
if (!textFieldContentEl) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const currentContentEl = current && current[0] ? current[0].getContentElement() : null;
|
|
345
|
+
if (currentContentEl) {
|
|
346
|
+
textFieldContentEl.setAttribute("aria-activedescendant", currentContentEl.getAttribute("id"));
|
|
347
|
+
} else {
|
|
348
|
+
textFieldContentEl.removeAttribute("aria-activedescendant");
|
|
349
|
+
}
|
|
336
350
|
},
|
|
337
351
|
|
|
338
352
|
|
|
@@ -363,16 +377,6 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
363
377
|
list.resetSelection();
|
|
364
378
|
}
|
|
365
379
|
}
|
|
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
380
|
|
|
377
381
|
// In all cases: Remove focused state from button
|
|
378
382
|
this.getChildControl("button").removeState("selected");
|
|
@@ -390,11 +394,12 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
390
394
|
var value = e.getData();
|
|
391
395
|
|
|
392
396
|
var list = this.getChildControl("list");
|
|
397
|
+
let current = null;
|
|
393
398
|
if (value != null) {
|
|
394
399
|
// Select item when possible
|
|
395
|
-
|
|
396
|
-
if (
|
|
397
|
-
list.setSelection([
|
|
400
|
+
current = list.findItem(value, false);
|
|
401
|
+
if (current) {
|
|
402
|
+
list.setSelection([current]);
|
|
398
403
|
} else {
|
|
399
404
|
list.resetSelection();
|
|
400
405
|
}
|
|
@@ -402,6 +407,15 @@ qx.Class.define("qx.ui.form.ComboBox",
|
|
|
402
407
|
list.resetSelection();
|
|
403
408
|
}
|
|
404
409
|
|
|
410
|
+
// ARIA attrs
|
|
411
|
+
const old = e.getOldData() ? list.findItem(e.getOldData(), false) : null;
|
|
412
|
+
if (old && old !== current) {
|
|
413
|
+
old.getContentElement().setAttribute("aria-selected", false);
|
|
414
|
+
}
|
|
415
|
+
if (current) {
|
|
416
|
+
current.getContentElement().setAttribute("aria-selected", true);
|
|
417
|
+
}
|
|
418
|
+
|
|
405
419
|
// Fire event
|
|
406
420
|
this.fireDataEvent("changeValue", value, e.getOldData());
|
|
407
421
|
},
|
|
@@ -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
|
|
|
@@ -120,6 +123,21 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
120
123
|
value.removeState("submenu");
|
|
121
124
|
value.removeState("contextmenu");
|
|
122
125
|
}
|
|
126
|
+
|
|
127
|
+
// ARIA attrs
|
|
128
|
+
const contentEl = this.getContentElement();
|
|
129
|
+
if (!contentEl) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (value) {
|
|
133
|
+
contentEl.setAttribute("aria-haspopup", "menu");
|
|
134
|
+
contentEl.setAttribute("aria-expanded", value.isVisible());
|
|
135
|
+
contentEl.setAttribute("aria-controls", value.getContentElement().getAttribute("id"));
|
|
136
|
+
} else {
|
|
137
|
+
contentEl.removeAttribute("aria-haspopup");
|
|
138
|
+
contentEl.removeAttribute("aria-expanded");
|
|
139
|
+
contentEl.removeAttribute("aria-controls");
|
|
140
|
+
}
|
|
123
141
|
},
|
|
124
142
|
|
|
125
143
|
|
|
@@ -142,6 +160,10 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
142
160
|
|
|
143
161
|
if (menu)
|
|
144
162
|
{
|
|
163
|
+
// Focus this button when the menu opens
|
|
164
|
+
if (this.isFocusable() && !qx.ui.core.FocusHandler.getInstance().isFocused(this)) {
|
|
165
|
+
this.focus();
|
|
166
|
+
}
|
|
145
167
|
// Hide all menus first
|
|
146
168
|
qx.ui.menu.Manager.getInstance().hideAll();
|
|
147
169
|
|
|
@@ -177,12 +199,15 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
177
199
|
_onMenuChange : function(e)
|
|
178
200
|
{
|
|
179
201
|
var menu = this.getMenu();
|
|
180
|
-
|
|
181
|
-
if (
|
|
202
|
+
const menuVisible = menu.isVisible()
|
|
203
|
+
if (menuVisible) {
|
|
182
204
|
this.addState("pressed");
|
|
183
205
|
} else {
|
|
184
206
|
this.removeState("pressed");
|
|
185
207
|
}
|
|
208
|
+
|
|
209
|
+
// ARIA attrs
|
|
210
|
+
this.getContentElement().setAttribute("aria-expanded", menuVisible);
|
|
186
211
|
},
|
|
187
212
|
|
|
188
213
|
|
|
@@ -241,6 +266,7 @@ qx.Class.define("qx.ui.form.MenuButton",
|
|
|
241
266
|
{
|
|
242
267
|
switch(e.getKeyIdentifier())
|
|
243
268
|
{
|
|
269
|
+
case "Space":
|
|
244
270
|
case "Enter":
|
|
245
271
|
this.removeState("abandoned");
|
|
246
272
|
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,18 @@ qx.Class.define("qx.ui.form.SelectBox",
|
|
|
413
428
|
{
|
|
414
429
|
this.resetSelection();
|
|
415
430
|
}
|
|
431
|
+
|
|
432
|
+
// Set aria-activedescendant
|
|
433
|
+
const contentEl = this.getContentElement();
|
|
434
|
+
if (!contentEl) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
const currentContentEl = current && current[0] ? current[0].getContentElement() : null;
|
|
438
|
+
if (currentContentEl) {
|
|
439
|
+
contentEl.setAttribute("aria-activedescendant", currentContentEl.getAttribute("id"));
|
|
440
|
+
} else {
|
|
441
|
+
contentEl.removeAttribute("aria-activedescendant");
|
|
442
|
+
}
|
|
416
443
|
},
|
|
417
444
|
|
|
418
445
|
// overridden
|
|
@@ -82,6 +82,9 @@ qx.Class.define("qx.ui.form.Slider",
|
|
|
82
82
|
// Force canvas layout
|
|
83
83
|
this._setLayout(new qx.ui.layout.Canvas());
|
|
84
84
|
|
|
85
|
+
// ARIA attrs
|
|
86
|
+
this.getContentElement().setAttribute("role", "slider");
|
|
87
|
+
|
|
85
88
|
// Add listeners
|
|
86
89
|
this.addListener("keypress", this._onKeyPress);
|
|
87
90
|
this.addListener("roll", this._onRoll);
|
|
@@ -1024,6 +1027,9 @@ qx.Class.define("qx.ui.form.Slider",
|
|
|
1024
1027
|
// property apply
|
|
1025
1028
|
_applyOrientation : function(value, old)
|
|
1026
1029
|
{
|
|
1030
|
+
// ARIA attrs
|
|
1031
|
+
this.getContentElement().setAttribute("aria-orientation", value);
|
|
1032
|
+
|
|
1027
1033
|
var knob = this.getChildControl("knob");
|
|
1028
1034
|
|
|
1029
1035
|
// Update private flag for faster access
|
|
@@ -1077,6 +1083,9 @@ qx.Class.define("qx.ui.form.Slider",
|
|
|
1077
1083
|
// property apply
|
|
1078
1084
|
_applyValue : function(value, old) {
|
|
1079
1085
|
if (value != null) {
|
|
1086
|
+
// ARIA attrs
|
|
1087
|
+
this.getContentElement().setAttribute("aria-valuenow", value);
|
|
1088
|
+
|
|
1080
1089
|
this._updateKnobPosition();
|
|
1081
1090
|
if (this.__dragMode) {
|
|
1082
1091
|
this.__dragValue = [value,old];
|
|
@@ -1105,6 +1114,9 @@ qx.Class.define("qx.ui.form.Slider",
|
|
|
1105
1114
|
// property apply
|
|
1106
1115
|
_applyMinimum : function(value, old)
|
|
1107
1116
|
{
|
|
1117
|
+
// ARIA attrs
|
|
1118
|
+
this.getContentElement().setAttribute("aria-valuemin", value);
|
|
1119
|
+
|
|
1108
1120
|
if (this.getValue() < value) {
|
|
1109
1121
|
this.setValue(value);
|
|
1110
1122
|
}
|
|
@@ -1116,6 +1128,9 @@ qx.Class.define("qx.ui.form.Slider",
|
|
|
1116
1128
|
// property apply
|
|
1117
1129
|
_applyMaximum : function(value, old)
|
|
1118
1130
|
{
|
|
1131
|
+
// ARIA attrs
|
|
1132
|
+
this.getContentElement().setAttribute("aria-valuemax", value);
|
|
1133
|
+
|
|
1119
1134
|
if (this.getValue() > value) {
|
|
1120
1135
|
this.setValue(value);
|
|
1121
1136
|
}
|
|
@@ -65,6 +65,10 @@ qx.Class.define("qx.ui.form.ToggleButton",
|
|
|
65
65
|
// register execute event
|
|
66
66
|
this.addListener("execute", this._onExecute, this);
|
|
67
67
|
|
|
68
|
+
// ARIA attrs
|
|
69
|
+
const contentEl = this.getContentElement();
|
|
70
|
+
contentEl.setAttribute("role", "button");
|
|
71
|
+
contentEl.setAttribute("aria-pressed", false);
|
|
68
72
|
},
|
|
69
73
|
|
|
70
74
|
|
|
@@ -159,13 +163,17 @@ qx.Class.define("qx.ui.form.ToggleButton",
|
|
|
159
163
|
_applyValue : function(value, old) {
|
|
160
164
|
value ? this.addState("checked") : this.removeState("checked");
|
|
161
165
|
|
|
166
|
+
let ariaPressed = Boolean(value);
|
|
162
167
|
if (this.isTriState()) {
|
|
163
168
|
if (value === null) {
|
|
169
|
+
ariaPressed = "mixed";
|
|
164
170
|
this.addState("undetermined");
|
|
165
171
|
} else if (old === null) {
|
|
166
172
|
this.removeState("undetermined");
|
|
167
173
|
}
|
|
168
174
|
}
|
|
175
|
+
|
|
176
|
+
this.getContentElement().setAttribute("aria-pressed", ariaPressed);
|
|
169
177
|
},
|
|
170
178
|
|
|
171
179
|
/**
|