1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
|
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Selection event tests">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
<script type="application/javascript"
src="../common.js" />
<script type="application/javascript"
src="../role.js" />
<script type="application/javascript"
src="../states.js" />
<script type="application/javascript"
src="../events.js" />
<script type="application/javascript">
function advanceTab(aTabsID, aDirection, aNextTabID)
{
var eventSeq1 = [
new invokerChecker(EVENT_SELECTION, aNextTabID)
]
defineScenario(this, eventSeq1);
var eventSeq2 = [
new invokerChecker(EVENT_HIDE, getAccessible(aNextTabID)),
new invokerChecker(EVENT_SHOW, aNextTabID)
];
defineScenario(this, eventSeq2);
this.invoke = function advanceTab_invoke()
{
todo(false, "No accessible recreation should happen, just selection event");
getNode(aTabsID).advanceSelectedTab(aDirection, true);
}
this.getID = function synthFocus_getID()
{
return "advanceTab on " + prettyName(aTabsID) + " to " + prettyName(aNextTabID);
}
}
function select4FirstItems(aID)
{
this.listboxNode = getNode(aID);
this.eventSeq = [
new invokerChecker(EVENT_SELECTION_ADD, this.listboxNode.getItemAtIndex(0)),
new invokerChecker(EVENT_SELECTION_ADD, this.listboxNode.getItemAtIndex(1)),
new invokerChecker(EVENT_SELECTION_ADD, this.listboxNode.getItemAtIndex(2)),
new invokerChecker(EVENT_SELECTION_ADD, this.listboxNode.getItemAtIndex(3))
];
this.invoke = function select4FirstItems_invoke()
{
synthesizeKey("VK_DOWN", { shiftKey: true }); // selects two items
synthesizeKey("VK_DOWN", { shiftKey: true });
synthesizeKey("VK_DOWN", { shiftKey: true });
}
this.getID = function select4FirstItems_getID()
{
return "select 4 first items for " + prettyName(aID);
}
}
function unselect4FirstItems(aID)
{
this.listboxNode = getNode(aID);
this.eventSeq = [
new invokerChecker(EVENT_SELECTION_REMOVE, this.listboxNode.getItemAtIndex(3)),
new invokerChecker(EVENT_SELECTION_REMOVE, this.listboxNode.getItemAtIndex(2)),
new invokerChecker(EVENT_SELECTION_REMOVE, this.listboxNode.getItemAtIndex(1)),
new invokerChecker(EVENT_SELECTION_REMOVE, this.listboxNode.getItemAtIndex(0))
];
this.invoke = function unselect4FirstItems_invoke()
{
synthesizeKey("VK_UP", { shiftKey: true });
synthesizeKey("VK_UP", { shiftKey: true });
synthesizeKey("VK_UP", { shiftKey: true });
synthesizeKey(" ", { ctrlKey: true }); // unselect first item
}
this.getID = function unselect4FirstItems_getID()
{
return "unselect 4 first items for " + prettyName(aID);
}
}
function selectAllItems(aID)
{
this.listboxNode = getNode(aID);
this.eventSeq = [
new invokerChecker(EVENT_SELECTION_WITHIN, getAccessible(this.listboxNode))
];
this.invoke = function selectAllItems_invoke()
{
synthesizeKey("VK_END", { shiftKey: true });
}
this.getID = function selectAllItems_getID()
{
return "select all items for " + prettyName(aID);
}
}
function unselectAllItemsButFirst(aID)
{
this.listboxNode = getNode(aID);
this.eventSeq = [
new invokerChecker(EVENT_SELECTION_WITHIN, getAccessible(this.listboxNode))
];
this.invoke = function unselectAllItemsButFirst_invoke()
{
synthesizeKey("VK_HOME", { shiftKey: true });
}
this.getID = function unselectAllItemsButFirst_getID()
{
return "unselect all items for " + prettyName(aID);
}
}
function unselectSelectItem(aID)
{
this.listboxNode = getNode(aID);
this.eventSeq = [
new invokerChecker(EVENT_SELECTION_REMOVE, this.listboxNode.getItemAtIndex(0)),
new invokerChecker(EVENT_SELECTION_ADD, this.listboxNode.getItemAtIndex(0))
];
this.invoke = function unselectSelectItem_invoke()
{
synthesizeKey(" ", { ctrlKey: true }); // select item
synthesizeKey(" ", { ctrlKey: true }); // unselect item
}
this.getID = function unselectSelectItem_getID()
{
return "unselect and then select first item for " + prettyName(aID);
}
}
/**
* Do tests.
*/
var gQueue = null;
//enableLogging("events");
//gA11yEventDumpToConsole = true; // debuggin
function doTests()
{
gQueue = new eventQueue();
//////////////////////////////////////////////////////////////////////////
// tabbox
gQueue.push(new advanceTab("tabs", 1, "tab3"));
//////////////////////////////////////////////////////////////////////////
// single selection listbox, the first item is selected by default
gQueue.push(new synthClick("lb1_item2",
new invokerChecker(EVENT_SELECTION, "lb1_item2")));
gQueue.push(new synthUpKey("lb1_item2",
new invokerChecker(EVENT_SELECTION, "lb1_item1")));
gQueue.push(new synthDownKey("lb1_item1",
new invokerChecker(EVENT_SELECTION, "lb1_item2")));
//////////////////////////////////////////////////////////////////////////
// multiselectable listbox
gQueue.push(new synthClick("lb2_item1",
new invokerChecker(EVENT_SELECTION, "lb2_item1")));
gQueue.push(new synthDownKey("lb2_item1",
new invokerChecker(EVENT_SELECTION_ADD, "lb2_item2"),
{ shiftKey: true }));
gQueue.push(new synthUpKey("lb2_item2",
new invokerChecker(EVENT_SELECTION_REMOVE, "lb2_item2"),
{ shiftKey: true }));
gQueue.push(new synthKey("lb2_item1", " ", { ctrlKey: true },
new invokerChecker(EVENT_SELECTION_REMOVE, "lb2_item1")));
//////////////////////////////////////////////////////////////////////////
// selection event coalescence
// fire 4 selection_add events
gQueue.push(new select4FirstItems("listbox2"));
// fire 4 selection_remove events
gQueue.push(new unselect4FirstItems("listbox2"));
// fire selection_within event
gQueue.push(new selectAllItems("listbox2"));
// fire selection_within event
gQueue.push(new unselectAllItemsButFirst("listbox2"));
// fire selection_remove/add events
gQueue.push(new unselectSelectItem("listbox2"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=414302"
title="Incorrect selection events in HTML, XUL and ARIA">
Mozilla Bug 414302
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
<tabbox id="tabbox" selectedIndex="1">
<tabs id="tabs">
<tab id="tab1" label="tab1"/>
<tab id="tab2" label="tab2"/>
<tab id="tab3" label="tab3"/>
<tab id="tab4" label="tab4"/>
</tabs>
<tabpanels>
<tabpanel><!-- tabpanel First elements go here --></tabpanel>
<tabpanel><button id="b1" label="b1"/></tabpanel>
<tabpanel><button id="b2" label="b2"/></tabpanel>
<tabpanel></tabpanel>
</tabpanels>
</tabbox>
<richlistbox id="listbox">
<richlistitem id="lb1_item1"><label value="item1"/></richlistitem>
<richlistitem id="lb1_item2"><label value="item2"/></richlistitem>
</richlistbox>
<richlistbox id="listbox2" seltype="multiple">
<richlistitem id="lb2_item1"><label value="item1"/></richlistitem>
<richlistitem id="lb2_item2"><label value="item2"/></richlistitem>
<richlistitem id="lb2_item3"><label value="item3"/></richlistitem>
<richlistitem id="lb2_item4"><label value="item4"/></richlistitem>
<richlistitem id="lb2_item5"><label value="item5"/></richlistitem>
<richlistitem id="lb2_item6"><label value="item6"/></richlistitem>
<richlistitem id="lb2_item7"><label value="item7"/></richlistitem>
</richlistbox>
</hbox>
</window>
|