@gtkx/testing 1.0.0-rc.4 → 1.0.0
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/README.md +5 -5
- package/dist/accessible-native.d.ts +16 -0
- package/dist/accessible-native.d.ts.map +1 -0
- package/dist/accessible-native.js +206 -0
- package/dist/accessible-native.js.map +1 -0
- package/dist/build-queries.d.ts +27 -10
- package/dist/build-queries.d.ts.map +1 -1
- package/dist/build-queries.js +22 -24
- package/dist/build-queries.js.map +1 -1
- package/dist/cleanup-registry.d.ts +1 -1
- package/dist/cleanup-registry.d.ts.map +1 -1
- package/dist/cleanup-registry.js.map +1 -1
- package/dist/errors.d.ts +10 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +10 -1
- package/dist/errors.js.map +1 -1
- package/dist/fire-event.d.ts +35 -6
- package/dist/fire-event.d.ts.map +1 -1
- package/dist/fire-event.js +23 -7
- package/dist/fire-event.js.map +1 -1
- package/dist/frame-sync.d.ts +2 -1
- package/dist/frame-sync.d.ts.map +1 -1
- package/dist/frame-sync.js +15 -5
- package/dist/frame-sync.js.map +1 -1
- package/dist/harness-window.d.ts +4 -0
- package/dist/harness-window.d.ts.map +1 -0
- package/dist/harness-window.js +6 -0
- package/dist/harness-window.js.map +1 -0
- package/dist/index.d.ts +14 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +4 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +4 -0
- package/dist/internal.js.map +1 -0
- package/dist/matchers.d.ts +88 -46
- package/dist/matchers.d.ts.map +1 -1
- package/dist/matchers.js +156 -18
- package/dist/matchers.js.map +1 -1
- package/dist/pretty-format.d.ts +2 -0
- package/dist/pretty-format.d.ts.map +1 -0
- package/dist/pretty-format.js +2 -0
- package/dist/pretty-format.js.map +1 -0
- package/dist/pretty-widget.d.ts +5 -2
- package/dist/pretty-widget.d.ts.map +1 -1
- package/dist/pretty-widget.js +73 -56
- package/dist/pretty-widget.js.map +1 -1
- package/dist/production.d.ts +8 -0
- package/dist/production.d.ts.map +1 -0
- package/dist/production.js +34 -0
- package/dist/production.js.map +1 -0
- package/dist/queries.d.ts +98 -56
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +123 -83
- package/dist/queries.js.map +1 -1
- package/dist/query-helpers.d.ts +44 -0
- package/dist/query-helpers.d.ts.map +1 -0
- package/dist/query-helpers.js +57 -0
- package/dist/query-helpers.js.map +1 -0
- package/dist/render-children.d.ts +9 -0
- package/dist/render-children.d.ts.map +1 -0
- package/dist/render-children.js +11 -0
- package/dist/render-children.js.map +1 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +11 -9
- package/dist/render.js.map +1 -1
- package/dist/role-helpers.d.ts +12 -3
- package/dist/role-helpers.d.ts.map +1 -1
- package/dist/role-helpers.js +13 -4
- package/dist/role-helpers.js.map +1 -1
- package/dist/role-naming.d.ts +5 -0
- package/dist/role-naming.d.ts.map +1 -0
- package/dist/role-naming.js +96 -0
- package/dist/role-naming.js.map +1 -0
- package/dist/screenshot.d.ts +12 -20
- package/dist/screenshot.d.ts.map +1 -1
- package/dist/screenshot.js +183 -91
- package/dist/screenshot.js.map +1 -1
- package/dist/traversal.d.ts +4 -1
- package/dist/traversal.d.ts.map +1 -1
- package/dist/traversal.js +25 -6
- package/dist/traversal.js.map +1 -1
- package/dist/types.d.ts +26 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/user-event/adjustment.d.ts +3 -0
- package/dist/user-event/adjustment.d.ts.map +1 -1
- package/dist/user-event/adjustment.js +23 -2
- package/dist/user-event/adjustment.js.map +1 -1
- package/dist/user-event/click.d.ts +43 -8
- package/dist/user-event/click.d.ts.map +1 -1
- package/dist/user-event/click.js +175 -44
- package/dist/user-event/click.js.map +1 -1
- package/dist/user-event/column-header-click.d.ts +4 -0
- package/dist/user-event/column-header-click.d.ts.map +1 -0
- package/dist/user-event/column-header-click.js +65 -0
- package/dist/user-event/column-header-click.js.map +1 -0
- package/dist/user-event/event-wrapper.d.ts.map +1 -1
- package/dist/user-event/event-wrapper.js +2 -1
- package/dist/user-event/event-wrapper.js.map +1 -1
- package/dist/user-event/index.d.ts +51 -10
- package/dist/user-event/index.d.ts.map +1 -1
- package/dist/user-event/index.js +43 -26
- package/dist/user-event/index.js.map +1 -1
- package/dist/user-event/indexed-children.d.ts +10 -0
- package/dist/user-event/indexed-children.d.ts.map +1 -0
- package/dist/user-event/indexed-children.js +50 -0
- package/dist/user-event/indexed-children.js.map +1 -0
- package/dist/user-event/keyboard.d.ts.map +1 -1
- package/dist/user-event/keyboard.js +33 -4
- package/dist/user-event/keyboard.js.map +1 -1
- package/dist/user-event/list-row-click.d.ts +4 -0
- package/dist/user-event/list-row-click.d.ts.map +1 -0
- package/dist/user-event/list-row-click.js +39 -0
- package/dist/user-event/list-row-click.js.map +1 -0
- package/dist/user-event/native-click.d.ts +6 -0
- package/dist/user-event/native-click.d.ts.map +1 -0
- package/dist/user-event/native-click.js +32 -0
- package/dist/user-event/native-click.js.map +1 -0
- package/dist/user-event/pointer.d.ts +1 -1
- package/dist/user-event/pointer.d.ts.map +1 -1
- package/dist/user-event/pointer.js +33 -9
- package/dist/user-event/pointer.js.map +1 -1
- package/dist/user-event/selection.d.ts +11 -8
- package/dist/user-event/selection.d.ts.map +1 -1
- package/dist/user-event/selection.js +49 -38
- package/dist/user-event/selection.js.map +1 -1
- package/dist/user-event/text.d.ts +6 -2
- package/dist/user-event/text.d.ts.map +1 -1
- package/dist/user-event/text.js +68 -18
- package/dist/user-event/text.js.map +1 -1
- package/dist/widget-accessible-properties.d.ts +14 -26
- package/dist/widget-accessible-properties.d.ts.map +1 -1
- package/dist/widget-accessible-properties.js +135 -190
- package/dist/widget-accessible-properties.js.map +1 -1
- package/dist/widget-getters.d.ts +8 -0
- package/dist/widget-getters.d.ts.map +1 -0
- package/dist/widget-getters.js +19 -0
- package/dist/widget-getters.js.map +1 -0
- package/dist/within.d.ts +3 -2
- package/dist/within.d.ts.map +1 -1
- package/dist/within.js +3 -2
- package/dist/within.js.map +1 -1
- package/package.json +12 -7
- package/src/accessible-native.ts +333 -0
- package/src/build-queries.ts +47 -41
- package/src/cleanup-registry.ts +1 -1
- package/src/errors.ts +12 -1
- package/src/fire-event.ts +61 -8
- package/src/frame-sync.ts +21 -5
- package/src/harness-window.ts +9 -0
- package/src/index.ts +18 -11
- package/src/internal.ts +11 -0
- package/src/matchers.ts +428 -70
- package/src/pretty-format.ts +1 -0
- package/src/pretty-widget.ts +97 -70
- package/src/production.ts +52 -0
- package/src/queries.ts +127 -89
- package/src/query-helpers.ts +97 -0
- package/src/render-children.ts +25 -0
- package/src/render.tsx +16 -11
- package/src/role-helpers.ts +14 -4
- package/src/role-naming.ts +99 -0
- package/src/screenshot.ts +272 -103
- package/src/traversal.ts +44 -6
- package/src/types.ts +28 -16
- package/src/user-event/adjustment.ts +29 -2
- package/src/user-event/click.ts +247 -52
- package/src/user-event/column-header-click.ts +90 -0
- package/src/user-event/event-wrapper.ts +3 -1
- package/src/user-event/index.ts +100 -37
- package/src/user-event/indexed-children.ts +75 -0
- package/src/user-event/keyboard.ts +52 -4
- package/src/user-event/list-row-click.ts +57 -0
- package/src/user-event/native-click.ts +46 -0
- package/src/user-event/pointer.ts +48 -9
- package/src/user-event/selection.ts +67 -41
- package/src/user-event/text.ts +92 -21
- package/src/widget-accessible-properties.ts +183 -230
- package/src/widget-getters.ts +32 -0
- package/src/within.ts +3 -2
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
isAccessibleNumberMatch,
|
|
4
|
+
readAccessibleBooleanProperty,
|
|
5
|
+
readAccessibleFlag,
|
|
6
|
+
readAccessibleInt,
|
|
7
|
+
readAccessibleRelation,
|
|
8
|
+
readAccessibleState,
|
|
9
|
+
readAccessibleNumber as readNativeNumber,
|
|
10
|
+
readAccessibleString as readNativeString,
|
|
11
|
+
} from "./accessible-native.js";
|
|
3
12
|
import { EDITABLE_ROLES, isEditable, readEditableText } from "./editable.js";
|
|
4
|
-
import {
|
|
13
|
+
import { isNameFromAuthor, isNameProhibited } from "./role-naming.js";
|
|
14
|
+
import { children, descendants, relationCandidates } from "./traversal.js";
|
|
15
|
+
import { callBooleanGetter, callStringGetter, getCallableMethod } from "./widget-getters.js";
|
|
5
16
|
|
|
6
|
-
type
|
|
7
|
-
now: number | null;
|
|
8
|
-
min: number | null;
|
|
9
|
-
max: number | null;
|
|
10
|
-
text: string | null;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
type ValueTriplet = { now: number | null; min: number | null; max: number | null };
|
|
17
|
+
type WidgetValueField = "now" | "min" | "max";
|
|
14
18
|
type CheckedState = "checked" | "unchecked" | "mixed";
|
|
15
19
|
|
|
16
|
-
const
|
|
20
|
+
const EDITABLE_TEXT_GETTER = "getText";
|
|
21
|
+
const DEFAULT_TEXT_GETTERS = ["getLabel", EDITABLE_TEXT_GETTER, "getTitle"];
|
|
17
22
|
|
|
18
23
|
const SELECTABLE_ROLES: Set<Gtk.AccessibleRole> = new Set<Gtk.AccessibleRole>([
|
|
19
24
|
Gtk.AccessibleRole.ROW,
|
|
@@ -23,55 +28,60 @@ const SELECTABLE_ROLES: Set<Gtk.AccessibleRole> = new Set<Gtk.AccessibleRole>([
|
|
|
23
28
|
Gtk.AccessibleRole.TREE_ITEM,
|
|
24
29
|
]);
|
|
25
30
|
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
31
|
+
const PRESSED_BY_TRISTATE: Map<number, boolean> = new Map<number, boolean>([
|
|
32
|
+
[Gtk.AccessibleTristate.FALSE, false],
|
|
33
|
+
[Gtk.AccessibleTristate.TRUE, true],
|
|
34
|
+
]);
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
const CHECKED_BY_TRISTATE: Map<number, CheckedState> = new Map<number, CheckedState>([
|
|
37
|
+
[Gtk.AccessibleTristate.FALSE, "unchecked"],
|
|
38
|
+
[Gtk.AccessibleTristate.TRUE, "checked"],
|
|
39
|
+
[Gtk.AccessibleTristate.MIXED, "mixed"],
|
|
40
|
+
]);
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
const VALUE_PROPERTIES: Record<WidgetValueField, Gtk.AccessibleProperty> = {
|
|
43
|
+
now: Gtk.AccessibleProperty.VALUE_NOW,
|
|
44
|
+
min: Gtk.AccessibleProperty.VALUE_MIN,
|
|
45
|
+
max: Gtk.AccessibleProperty.VALUE_MAX,
|
|
36
46
|
};
|
|
37
47
|
|
|
38
|
-
const readAccessibleString = (widget: Gtk.Widget,
|
|
39
|
-
|
|
48
|
+
const readAccessibleString = (widget: Gtk.Widget, property: Gtk.AccessibleProperty): string | null =>
|
|
49
|
+
readNativeString(widget, property);
|
|
40
50
|
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
const readAccessibleNumber = (widget: Gtk.Widget, property: Gtk.AccessibleProperty): number | null =>
|
|
52
|
+
readNativeNumber(widget, property);
|
|
43
53
|
|
|
44
|
-
const
|
|
45
|
-
const
|
|
54
|
+
const readAccessibleWidgets = (widget: Gtk.Widget, relation: Gtk.AccessibleRelation): Gtk.Widget[] | null => {
|
|
55
|
+
const targets = readAccessibleRelation(widget, relation, relationCandidates(widget));
|
|
56
|
+
const widgets = targets.filter((target): target is Gtk.Widget => target instanceof Gtk.Widget);
|
|
46
57
|
|
|
47
|
-
return
|
|
58
|
+
return widgets.length > 0 ? widgets : null;
|
|
48
59
|
};
|
|
49
60
|
|
|
50
|
-
const
|
|
51
|
-
|
|
61
|
+
const readAccessibleBoolean = (widget: Gtk.Widget, state: Gtk.AccessibleState): boolean | null =>
|
|
62
|
+
readAccessibleFlag(widget, state);
|
|
52
63
|
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
const getLabelText = (widget: Gtk.Widget): string | null => {
|
|
65
|
+
if (widget instanceof Gtk.Label) {
|
|
66
|
+
return widget.getLabel();
|
|
55
67
|
}
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return widgets.length > 0 ? widgets : null;
|
|
69
|
+
return readAccessibleString(widget, Gtk.AccessibleProperty.LABEL);
|
|
60
70
|
};
|
|
61
71
|
|
|
62
|
-
const
|
|
63
|
-
|
|
72
|
+
const stripMnemonic = (text: string): string => text.replaceAll(/_(.)/g, "$1");
|
|
73
|
+
const isUnderlineUsed = (widget: Gtk.Widget): boolean => callBooleanGetter(widget, "getUseUnderline") ?? false;
|
|
64
74
|
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
const readNamingText = (widget: Gtk.Widget, getter: string, value: string): string =>
|
|
76
|
+
getter !== EDITABLE_TEXT_GETTER && isUnderlineUsed(widget) ? stripMnemonic(value) : value;
|
|
67
77
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
78
|
+
const readFirstText = (widget: Gtk.Widget, getters: string[]): string | null => {
|
|
79
|
+
for (const getter of getters) {
|
|
80
|
+
const value = callStringGetter(widget, getter);
|
|
72
81
|
|
|
73
|
-
|
|
74
|
-
|
|
82
|
+
if (value) {
|
|
83
|
+
return readNamingText(widget, getter, value);
|
|
84
|
+
}
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
return null;
|
|
@@ -83,19 +93,7 @@ const getLabelText = (widget: Gtk.Widget): string | null => {
|
|
|
83
93
|
*
|
|
84
94
|
* @param widget The widget to read text from.
|
|
85
95
|
*/
|
|
86
|
-
const
|
|
87
|
-
for (const getter of DEFAULT_TEXT_GETTERS) {
|
|
88
|
-
const value = callStringGetter(widget, getter);
|
|
89
|
-
|
|
90
|
-
if (value) {
|
|
91
|
-
return value;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return null;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const stripMnemonic = (text: string): string => text.replaceAll(/_(.)/g, "$1");
|
|
96
|
+
const getWidgetText = (widget: Gtk.Widget): string | null => readFirstText(widget, DEFAULT_TEXT_GETTERS);
|
|
99
97
|
|
|
100
98
|
const namingLabelText = (widget: Gtk.Widget): string | null => {
|
|
101
99
|
const text = getLabelText(widget);
|
|
@@ -104,7 +102,7 @@ const namingLabelText = (widget: Gtk.Widget): string | null => {
|
|
|
104
102
|
return null;
|
|
105
103
|
}
|
|
106
104
|
|
|
107
|
-
return widget
|
|
105
|
+
return isUnderlineUsed(widget) ? stripMnemonic(text) : text;
|
|
108
106
|
};
|
|
109
107
|
|
|
110
108
|
const isNamingLabelRole = (role: Gtk.AccessibleRole, shouldIncludePresentation: boolean): boolean =>
|
|
@@ -135,49 +133,34 @@ const getWidgetLabelText = (widget: Gtk.Widget): string | null => {
|
|
|
135
133
|
return null;
|
|
136
134
|
}
|
|
137
135
|
|
|
138
|
-
return
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const getChildren = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {
|
|
142
|
-
let child = widget.getFirstChild();
|
|
143
|
-
|
|
144
|
-
while (child) {
|
|
145
|
-
yield child;
|
|
146
|
-
child = child.getNextSibling();
|
|
147
|
-
}
|
|
136
|
+
return namingLabelText(widget);
|
|
148
137
|
};
|
|
149
138
|
|
|
150
139
|
const textContentParts = (widget: Gtk.Widget): string[] => {
|
|
151
|
-
const own =
|
|
140
|
+
const own = getWidgetText(widget);
|
|
152
141
|
|
|
153
142
|
if (own !== null) {
|
|
154
143
|
return [own];
|
|
155
144
|
}
|
|
156
145
|
|
|
157
|
-
return [...
|
|
146
|
+
return [...children(widget)].flatMap((child) => textContentParts(child));
|
|
158
147
|
};
|
|
159
148
|
|
|
160
|
-
/**
|
|
161
|
-
* Returns a widget's own text, or the space-joined text of its descendants when it has none of its
|
|
162
|
-
* own, or null when neither produces a value.
|
|
163
|
-
*
|
|
164
|
-
* @param widget The widget whose subtree is read.
|
|
165
|
-
*/
|
|
166
149
|
const getWidgetTextContent = (widget: Gtk.Widget): string | null => {
|
|
167
150
|
const parts = textContentParts(widget);
|
|
168
151
|
|
|
169
152
|
return parts.length > 0 ? parts.join(" ") : null;
|
|
170
153
|
};
|
|
171
154
|
|
|
172
|
-
const
|
|
155
|
+
const isDropDownFaceCandidate = (widget: Gtk.Widget): boolean =>
|
|
173
156
|
!(widget instanceof Gtk.Popover) && widget.getChildVisible();
|
|
174
157
|
|
|
175
|
-
const
|
|
176
|
-
|
|
158
|
+
const dropDownChildFaceText = (child: Gtk.Widget): string | null =>
|
|
159
|
+
isDropDownFaceCandidate(child) ? getWidgetLabelText(child) ?? dropDownFaceText(child) : null;
|
|
177
160
|
|
|
178
|
-
const
|
|
179
|
-
for (const child of
|
|
180
|
-
const text =
|
|
161
|
+
const dropDownFaceText = (widget: Gtk.Widget): string | null => {
|
|
162
|
+
for (const child of children(widget)) {
|
|
163
|
+
const text = dropDownChildFaceText(child);
|
|
181
164
|
|
|
182
165
|
if (text !== null) {
|
|
183
166
|
return text;
|
|
@@ -197,67 +180,77 @@ const tabPanelTitle = (widget: Gtk.Widget): string | null => {
|
|
|
197
180
|
return null;
|
|
198
181
|
};
|
|
199
182
|
|
|
200
|
-
const
|
|
201
|
-
|
|
183
|
+
const nameFromAuthor = (widget: Gtk.Widget): string | null =>
|
|
184
|
+
getWidgetLabelledByText(widget) ?? readAccessibleString(widget, Gtk.AccessibleProperty.LABEL);
|
|
202
185
|
|
|
203
|
-
|
|
204
|
-
|
|
186
|
+
const nameFromContent = (widget: Gtk.Widget): string | null => {
|
|
187
|
+
const ownText = getWidgetText(widget);
|
|
188
|
+
|
|
189
|
+
if (ownText) {
|
|
190
|
+
return ownText;
|
|
205
191
|
}
|
|
206
192
|
|
|
207
|
-
const
|
|
193
|
+
const childLabels = collectLabels(widget);
|
|
208
194
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
195
|
+
return childLabels.length > 0 ? childLabels.join(" ") : null;
|
|
196
|
+
};
|
|
212
197
|
|
|
213
|
-
|
|
198
|
+
const getWidgetAccessibleName = (widget: Gtk.Widget): string | null => {
|
|
199
|
+
const role = widget.getAccessibleRole();
|
|
214
200
|
|
|
215
|
-
if (
|
|
216
|
-
return
|
|
201
|
+
if (isNameProhibited(role)) {
|
|
202
|
+
return null;
|
|
217
203
|
}
|
|
218
204
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (ownText) {
|
|
222
|
-
return ownText;
|
|
205
|
+
if (role === Gtk.AccessibleRole.TAB_PANEL) {
|
|
206
|
+
return tabPanelTitle(widget);
|
|
223
207
|
}
|
|
224
208
|
|
|
225
|
-
const
|
|
209
|
+
const authored = isNameFromAuthor(role) ? nameFromAuthor(widget) : null;
|
|
226
210
|
|
|
227
|
-
if (
|
|
228
|
-
return
|
|
211
|
+
if (authored) {
|
|
212
|
+
return authored;
|
|
229
213
|
}
|
|
230
214
|
|
|
231
|
-
return callStringGetter(widget, "getTooltipText");
|
|
215
|
+
return nameFromContent(widget) ?? callStringGetter(widget, "getTooltipText");
|
|
232
216
|
};
|
|
233
217
|
|
|
234
218
|
const getWidgetName = (widget: Gtk.Widget): string | null => {
|
|
235
219
|
return widget.getName();
|
|
236
220
|
};
|
|
237
221
|
|
|
238
|
-
const
|
|
239
|
-
if (!EDITABLE_ROLES.has(widget.getAccessibleRole()) || !(widget instanceof Gtk.Editable)) {
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
222
|
+
const nonEmptyText = (text: string | null): string | null => (text === null || text === "" ? null : text);
|
|
242
223
|
|
|
243
|
-
|
|
224
|
+
const readPlaceholderProperty = (widget: Gtk.Widget): string | null => {
|
|
225
|
+
const value: unknown = Reflect.get(widget, "placeholderText");
|
|
244
226
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
227
|
+
return typeof value === "string" ? nonEmptyText(value) : null;
|
|
228
|
+
};
|
|
248
229
|
|
|
249
|
-
|
|
230
|
+
const getWidgetPlaceholderText = (widget: Gtk.Widget): string | null => {
|
|
231
|
+
if (!EDITABLE_ROLES.has(widget.getAccessibleRole())) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
250
234
|
|
|
251
|
-
return
|
|
235
|
+
return (
|
|
236
|
+
nonEmptyText(callStringGetter(widget, "getPlaceholderText")) ??
|
|
237
|
+
readPlaceholderProperty(widget) ??
|
|
238
|
+
nonEmptyText(readAccessibleString(widget, Gtk.AccessibleProperty.PLACEHOLDER))
|
|
239
|
+
);
|
|
252
240
|
};
|
|
253
241
|
|
|
242
|
+
const comboBoxDisplayValue = (widget: Gtk.Widget): string | null =>
|
|
243
|
+
widget instanceof Gtk.DropDown
|
|
244
|
+
? (dropDownFaceText(widget) ?? getWidgetValueText(widget))
|
|
245
|
+
: (getWidgetValueText(widget) ?? dropDownFaceText(widget));
|
|
246
|
+
|
|
254
247
|
const getWidgetDisplayValue = (widget: Gtk.Widget): string | null => {
|
|
255
248
|
if (EDITABLE_ROLES.has(widget.getAccessibleRole()) && isEditable(widget)) {
|
|
256
249
|
return readEditableText(widget);
|
|
257
250
|
}
|
|
258
251
|
|
|
259
252
|
if (widget.getAccessibleRole() === Gtk.AccessibleRole.COMBO_BOX) {
|
|
260
|
-
return
|
|
253
|
+
return comboBoxDisplayValue(widget);
|
|
261
254
|
}
|
|
262
255
|
|
|
263
256
|
return null;
|
|
@@ -288,7 +281,7 @@ const hasZeroOpacityAncestor = (widget: Gtk.Widget): boolean => {
|
|
|
288
281
|
const isWidgetVisible = (widget: Gtk.Widget): boolean => widget.isVisible() && !hasZeroOpacityAncestor(widget);
|
|
289
282
|
|
|
290
283
|
const getWidgetRequiredState = (widget: Gtk.Widget): boolean | null =>
|
|
291
|
-
|
|
284
|
+
readAccessibleBooleanProperty(widget, Gtk.AccessibleProperty.REQUIRED);
|
|
292
285
|
|
|
293
286
|
const readTextViewSelection = (view: Gtk.TextView): string | null => {
|
|
294
287
|
const buffer = view.getBuffer();
|
|
@@ -297,40 +290,48 @@ const readTextViewSelection = (view: Gtk.TextView): string | null => {
|
|
|
297
290
|
return hasSelection ? buffer.getText(start, end, true) : null;
|
|
298
291
|
};
|
|
299
292
|
|
|
300
|
-
const
|
|
301
|
-
const [
|
|
293
|
+
const sliceSelectedText = (widget: Gtk.Widget, start: number, end: number): string | null => {
|
|
294
|
+
const chars = getCallableMethod<[number, number], string | null>(widget, "getChars");
|
|
295
|
+
|
|
296
|
+
if (chars) {
|
|
297
|
+
return chars(start, end) ?? null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const text = callStringGetter(widget, "getText");
|
|
302
301
|
|
|
303
|
-
|
|
302
|
+
/* eslint-disable-next-line @typescript-eslint/no-misused-spread -- bounds are code point offsets */
|
|
303
|
+
return text === null ? null : [...text].slice(start, end).join("");
|
|
304
304
|
};
|
|
305
305
|
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
return readTextViewSelection(widget);
|
|
309
|
-
}
|
|
306
|
+
const readBoundedSelection = (widget: Gtk.Widget): string | null => {
|
|
307
|
+
const bounds = getCallableMethod<[], [boolean, number, number]>(widget, "getSelectionBounds");
|
|
310
308
|
|
|
311
|
-
if (
|
|
312
|
-
return
|
|
309
|
+
if (!bounds) {
|
|
310
|
+
return null;
|
|
313
311
|
}
|
|
314
312
|
|
|
315
|
-
|
|
313
|
+
const [hasSelection, start, end] = bounds();
|
|
314
|
+
|
|
315
|
+
return hasSelection ? sliceSelectedText(widget, start, end) : null;
|
|
316
316
|
};
|
|
317
317
|
|
|
318
|
+
const getWidgetSelection = (widget: Gtk.Widget): string | null =>
|
|
319
|
+
widget instanceof Gtk.TextView ? readTextViewSelection(widget) : readBoundedSelection(widget);
|
|
320
|
+
|
|
318
321
|
const checkedFromActive = (isActive: boolean): CheckedState => (isActive ? "checked" : "unchecked");
|
|
319
322
|
|
|
320
|
-
const
|
|
321
|
-
widget instanceof Gtk.
|
|
322
|
-
(widget instanceof Gtk.ToggleButton && widget.getAccessibleRole() === Gtk.AccessibleRole.RADIO);
|
|
323
|
+
const isRadioToggle = (widget: Gtk.Widget): widget is Gtk.ToggleButton =>
|
|
324
|
+
widget instanceof Gtk.ToggleButton && widget.getAccessibleRole() === Gtk.AccessibleRole.RADIO;
|
|
323
325
|
|
|
324
326
|
const getWidgetCheckedState = (widget: Gtk.Widget): CheckedState | null => {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
327
|
+
const tristate = readAccessibleState(widget, Gtk.AccessibleState.CHECKED);
|
|
328
|
+
const state = tristate === null ? undefined : CHECKED_BY_TRISTATE.get(tristate);
|
|
328
329
|
|
|
329
|
-
if (
|
|
330
|
-
return
|
|
330
|
+
if (state !== undefined) {
|
|
331
|
+
return state;
|
|
331
332
|
}
|
|
332
333
|
|
|
333
|
-
return null;
|
|
334
|
+
return isRadioToggle(widget) ? checkedFromActive(widget.getActive()) : null;
|
|
334
335
|
};
|
|
335
336
|
|
|
336
337
|
const isWidgetChecked = (widget: Gtk.Widget): boolean | null => {
|
|
@@ -340,28 +341,24 @@ const isWidgetChecked = (widget: Gtk.Widget): boolean | null => {
|
|
|
340
341
|
};
|
|
341
342
|
|
|
342
343
|
const getWidgetPressedState = (widget: Gtk.Widget): boolean | null => {
|
|
343
|
-
|
|
344
|
-
return widget.getActive();
|
|
345
|
-
}
|
|
344
|
+
const tristate = readAccessibleState(widget, Gtk.AccessibleState.PRESSED);
|
|
346
345
|
|
|
347
|
-
return null;
|
|
346
|
+
return tristate === null ? null : PRESSED_BY_TRISTATE.get(tristate) ?? null;
|
|
348
347
|
};
|
|
349
348
|
|
|
350
349
|
const getWidgetExpandedState = (widget: Gtk.Widget): boolean | null => {
|
|
351
|
-
if (widget instanceof Gtk.Expander) {
|
|
352
|
-
return widget.getExpanded();
|
|
353
|
-
}
|
|
354
|
-
|
|
355
350
|
if (widget instanceof Gtk.TreeExpander) {
|
|
356
351
|
return widget.getListRow()?.getExpanded() ?? null;
|
|
357
352
|
}
|
|
358
353
|
|
|
359
|
-
return
|
|
354
|
+
return readAccessibleBoolean(widget, Gtk.AccessibleState.EXPANDED);
|
|
360
355
|
};
|
|
361
356
|
|
|
362
357
|
const getWidgetSelectedState = (widget: Gtk.Widget): boolean | null => {
|
|
363
|
-
|
|
364
|
-
|
|
358
|
+
const selected = readAccessibleBoolean(widget, Gtk.AccessibleState.SELECTED);
|
|
359
|
+
|
|
360
|
+
if (selected !== null) {
|
|
361
|
+
return selected;
|
|
365
362
|
}
|
|
366
363
|
|
|
367
364
|
if (SELECTABLE_ROLES.has(widget.getAccessibleRole())) {
|
|
@@ -372,99 +369,37 @@ const getWidgetSelectedState = (widget: Gtk.Widget): boolean | null => {
|
|
|
372
369
|
};
|
|
373
370
|
|
|
374
371
|
const getWidgetLevel = (widget: Gtk.Widget): number | null => {
|
|
375
|
-
return
|
|
372
|
+
return readAccessibleInt(widget, Gtk.AccessibleProperty.LEVEL);
|
|
376
373
|
};
|
|
377
374
|
|
|
378
|
-
/**
|
|
379
|
-
* Returns the accessible invalid state declared on a widget, or null when it declares none.
|
|
380
|
-
*
|
|
381
|
-
* @param widget The widget to read the state from.
|
|
382
|
-
*/
|
|
383
375
|
const getWidgetInvalidState = (widget: Gtk.Widget): Gtk.AccessibleInvalidState | null => {
|
|
384
|
-
const value =
|
|
376
|
+
const value = readAccessibleState(widget, Gtk.AccessibleState.INVALID);
|
|
385
377
|
|
|
386
378
|
return value ?? null;
|
|
387
379
|
};
|
|
388
380
|
|
|
389
|
-
/**
|
|
390
|
-
* Returns the widgets a widget's accessible error-message relation points at, or null when it
|
|
391
|
-
* declares none.
|
|
392
|
-
*
|
|
393
|
-
* @param widget The widget to read the relation from.
|
|
394
|
-
*/
|
|
395
381
|
const getWidgetErrorMessage = (widget: Gtk.Widget): Gtk.Widget[] | null =>
|
|
396
|
-
readAccessibleWidgets(widget,
|
|
382
|
+
readAccessibleWidgets(widget, Gtk.AccessibleRelation.ERROR_MESSAGE);
|
|
397
383
|
|
|
398
384
|
const getWidgetBusyState = (widget: Gtk.Widget): boolean | null => {
|
|
399
|
-
return readAccessibleBoolean(widget,
|
|
385
|
+
return readAccessibleBoolean(widget, Gtk.AccessibleState.BUSY);
|
|
400
386
|
};
|
|
401
387
|
|
|
402
388
|
const getWidgetDescription = (widget: Gtk.Widget): string | null => {
|
|
403
|
-
return readAccessibleString(widget,
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
const adjustmentValue = (adjustment: Gtk.Adjustment): ValueTriplet => ({
|
|
407
|
-
now: adjustment.getValue(),
|
|
408
|
-
min: adjustment.getLower(),
|
|
409
|
-
max: adjustment.getUpper(),
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
const adjustmentWidgetValue = (widget: Gtk.Widget): ValueTriplet | null => {
|
|
413
|
-
if (widget instanceof Gtk.Range) {
|
|
414
|
-
return adjustmentValue(widget.getAdjustment());
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
if (widget instanceof Gtk.Scrollbar) {
|
|
418
|
-
return adjustmentValue(widget.getAdjustment());
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
if (widget instanceof Gtk.SpinButton) {
|
|
422
|
-
return adjustmentValue(widget.getAdjustment());
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
if (widget instanceof Gtk.ScaleButton) {
|
|
426
|
-
return adjustmentValue(widget.getAdjustment());
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
return null;
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
const getWidgetLiveValue = (widget: Gtk.Widget): ValueTriplet | null => {
|
|
433
|
-
const adjustmentBased = adjustmentWidgetValue(widget);
|
|
434
|
-
|
|
435
|
-
if (adjustmentBased) {
|
|
436
|
-
return adjustmentBased;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (widget instanceof Gtk.LevelBar) {
|
|
440
|
-
return { now: widget.getValue(), min: widget.getMinValue(), max: widget.getMaxValue() };
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
if (widget instanceof Gtk.ProgressBar) {
|
|
444
|
-
return { now: widget.getFraction(), min: 0, max: 1 };
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
return null;
|
|
389
|
+
return readAccessibleString(widget, Gtk.AccessibleProperty.DESCRIPTION);
|
|
448
390
|
};
|
|
449
391
|
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
const live = getWidgetLiveValue(widget);
|
|
392
|
+
const getWidgetValueNow = (widget: Gtk.Widget): number | null =>
|
|
393
|
+
readAccessibleNumber(widget, Gtk.AccessibleProperty.VALUE_NOW);
|
|
453
394
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
}
|
|
395
|
+
const getWidgetValueText = (widget: Gtk.Widget): string | null =>
|
|
396
|
+
readAccessibleString(widget, Gtk.AccessibleProperty.VALUE_TEXT);
|
|
457
397
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
min: readAccessibleNumber(widget, "accessibleValueMin"),
|
|
461
|
-
max: readAccessibleNumber(widget, "accessibleValueMax"),
|
|
462
|
-
text,
|
|
463
|
-
};
|
|
464
|
-
};
|
|
398
|
+
const isWidgetValueMatch = (widget: Gtk.Widget, field: WidgetValueField, expected: number): boolean =>
|
|
399
|
+
isAccessibleNumberMatch(widget, VALUE_PROPERTIES[field], expected);
|
|
465
400
|
|
|
466
401
|
const getWidgetOwnLabel = (widget: Gtk.Widget): string | null => {
|
|
467
|
-
return readAccessibleString(widget,
|
|
402
|
+
return readAccessibleString(widget, Gtk.AccessibleProperty.LABEL);
|
|
468
403
|
};
|
|
469
404
|
|
|
470
405
|
const collectAccessibleNames = (targets: Gtk.Widget[]): string[] => {
|
|
@@ -473,7 +408,7 @@ const collectAccessibleNames = (targets: Gtk.Widget[]): string[] => {
|
|
|
473
408
|
for (const target of targets) {
|
|
474
409
|
const text = getWidgetAccessibleName(target);
|
|
475
410
|
|
|
476
|
-
if (text
|
|
411
|
+
if (text) {
|
|
477
412
|
texts.push(text);
|
|
478
413
|
}
|
|
479
414
|
}
|
|
@@ -481,8 +416,14 @@ const collectAccessibleNames = (targets: Gtk.Widget[]): string[] => {
|
|
|
481
416
|
return texts;
|
|
482
417
|
};
|
|
483
418
|
|
|
419
|
+
const isSelfLabelling = (widget: Gtk.Widget, targets: Gtk.Widget[]): boolean => {
|
|
420
|
+
const own = new Set(descendants(widget));
|
|
421
|
+
|
|
422
|
+
return targets.every((target) => own.has(target));
|
|
423
|
+
};
|
|
424
|
+
|
|
484
425
|
const getWidgetLabelledByText = (widget: Gtk.Widget): string | null => {
|
|
485
|
-
const targets = readAccessibleWidgets(widget,
|
|
426
|
+
const targets = readAccessibleWidgets(widget, Gtk.AccessibleRelation.LABELLED_BY);
|
|
486
427
|
|
|
487
428
|
if (targets === null) {
|
|
488
429
|
return null;
|
|
@@ -493,20 +434,26 @@ const getWidgetLabelledByText = (widget: Gtk.Widget): string | null => {
|
|
|
493
434
|
return texts.length > 0 ? texts.join(" ") : null;
|
|
494
435
|
};
|
|
495
436
|
|
|
437
|
+
const getWidgetExternalLabelText = (widget: Gtk.Widget): string | null => {
|
|
438
|
+
const targets = readAccessibleWidgets(widget, Gtk.AccessibleRelation.LABELLED_BY);
|
|
439
|
+
|
|
440
|
+
return targets === null || isSelfLabelling(widget, targets) ? null : getWidgetLabelledByText(widget);
|
|
441
|
+
};
|
|
442
|
+
|
|
496
443
|
const isTooltipUsedAsName = (widget: Gtk.Widget): boolean =>
|
|
497
|
-
readAccessibleString(widget,
|
|
498
|
-
|
|
444
|
+
readAccessibleString(widget, Gtk.AccessibleProperty.LABEL) === null &&
|
|
445
|
+
getWidgetText(widget) === null &&
|
|
499
446
|
collectLabels(widget).length === 0;
|
|
500
447
|
|
|
501
448
|
const getWidgetDescribedByText = (widget: Gtk.Widget): string | null => {
|
|
502
|
-
const targets = readAccessibleWidgets(widget,
|
|
449
|
+
const targets = readAccessibleWidgets(widget, Gtk.AccessibleRelation.DESCRIBED_BY);
|
|
503
450
|
const texts = targets === null ? [] : collectAccessibleNames(targets);
|
|
504
451
|
|
|
505
452
|
if (texts.length > 0) {
|
|
506
453
|
return texts.join(" ");
|
|
507
454
|
}
|
|
508
455
|
|
|
509
|
-
const description = readAccessibleString(widget,
|
|
456
|
+
const description = readAccessibleString(widget, Gtk.AccessibleProperty.DESCRIPTION);
|
|
510
457
|
|
|
511
458
|
if (description !== null) {
|
|
512
459
|
return description;
|
|
@@ -515,15 +462,17 @@ const getWidgetDescribedByText = (widget: Gtk.Widget): string | null => {
|
|
|
515
462
|
return isTooltipUsedAsName(widget) ? null : callStringGetter(widget, "getTooltipText");
|
|
516
463
|
};
|
|
517
464
|
|
|
465
|
+
/**
|
|
466
|
+
* Returns whether a widget is excluded from the accessibility tree, because it or one of its
|
|
467
|
+
* ancestors is marked hidden.
|
|
468
|
+
*
|
|
469
|
+
* @param widget The widget to test.
|
|
470
|
+
*/
|
|
518
471
|
const isInaccessible = (widget: Gtk.Widget): boolean => {
|
|
519
472
|
let current: Gtk.Widget | null = widget;
|
|
520
473
|
|
|
521
474
|
while (current) {
|
|
522
|
-
if (
|
|
523
|
-
return true;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
if (readAccessibleBoolean(current, "accessibleHidden") === true) {
|
|
475
|
+
if (readAccessibleBoolean(current, Gtk.AccessibleState.HIDDEN) === true) {
|
|
527
476
|
return true;
|
|
528
477
|
}
|
|
529
478
|
|
|
@@ -534,7 +483,8 @@ const isInaccessible = (widget: Gtk.Widget): boolean => {
|
|
|
534
483
|
};
|
|
535
484
|
|
|
536
485
|
export {
|
|
537
|
-
|
|
486
|
+
namingLabelText,
|
|
487
|
+
getWidgetText,
|
|
538
488
|
getWidgetTextContent,
|
|
539
489
|
getWidgetLabelText,
|
|
540
490
|
getWidgetAccessibleName,
|
|
@@ -557,10 +507,13 @@ export {
|
|
|
557
507
|
getWidgetErrorMessage,
|
|
558
508
|
getWidgetBusyState,
|
|
559
509
|
getWidgetDescription,
|
|
560
|
-
|
|
510
|
+
getWidgetValueNow,
|
|
511
|
+
getWidgetValueText,
|
|
561
512
|
getWidgetOwnLabel,
|
|
513
|
+
getWidgetExternalLabelText,
|
|
562
514
|
getWidgetLabelledByText,
|
|
563
515
|
isInaccessible,
|
|
516
|
+
isWidgetValueMatch,
|
|
564
517
|
type CheckedState,
|
|
565
|
-
type
|
|
518
|
+
type WidgetValueField,
|
|
566
519
|
};
|