mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 810268 - there's no way to know unselected item when selection in single selection was changed, r=tbsaunde
This commit is contained in:
parent
238b6bebd6
commit
25db64d524
@ -303,7 +303,7 @@ EventQueue::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
|
||||
aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) {
|
||||
aTailEvent->mEventRule = AccEvent::eDoNotEmit;
|
||||
aThisEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION;
|
||||
aThisEvent->mPackedEvent = aThisEvent;
|
||||
aThisEvent->mPackedEvent = aTailEvent;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -472,6 +472,29 @@ EventQueue::ProcessEventQueue()
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fire selected state change events in support to selection events.
|
||||
if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_ADD) {
|
||||
nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
|
||||
true, event->mIsFromUserInput);
|
||||
|
||||
} else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION_REMOVE) {
|
||||
nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
|
||||
false, event->mIsFromUserInput);
|
||||
|
||||
} else if (event->mEventType == nsIAccessibleEvent::EVENT_SELECTION) {
|
||||
AccSelChangeEvent* selChangeEvent = downcast_accEvent(event);
|
||||
nsEventShell::FireEvent(event->mAccessible, states::SELECTED,
|
||||
(selChangeEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
|
||||
event->mIsFromUserInput);
|
||||
|
||||
if (selChangeEvent->mPackedEvent) {
|
||||
nsEventShell::FireEvent(selChangeEvent->mPackedEvent->mAccessible,
|
||||
states::SELECTED,
|
||||
(selChangeEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd),
|
||||
selChangeEvent->mPackedEvent->mIsFromUserInput);
|
||||
}
|
||||
}
|
||||
|
||||
nsEventShell::FireEvent(event);
|
||||
|
||||
// Fire text change events.
|
||||
|
@ -35,6 +35,20 @@ public:
|
||||
mozilla::a11y::Accessible* aAccessible,
|
||||
mozilla::a11y::EIsFromUserInput aIsFromUserInput = mozilla::a11y::eAutoDetect);
|
||||
|
||||
/**
|
||||
* Fire state change event.
|
||||
*/
|
||||
static void FireEvent(mozilla::a11y::Accessible* aTarget, uint64_t aState,
|
||||
bool aIsEnabled, bool aIsFromUserInput)
|
||||
{
|
||||
nsRefPtr<mozilla::a11y::AccStateChangeEvent> stateChangeEvent =
|
||||
new mozilla::a11y::AccStateChangeEvent(aTarget, aState, aIsEnabled,
|
||||
(aIsFromUserInput ?
|
||||
mozilla::a11y::eFromUserInput :
|
||||
mozilla::a11y::eNoUserInput));
|
||||
FireEvent(stateChangeEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append 'event-from-input' object attribute if the accessible event has
|
||||
* been fired just now for the given node.
|
||||
|
@ -508,7 +508,7 @@ function eventQueue(aEventType)
|
||||
}
|
||||
}
|
||||
|
||||
var matchedChecker = null;
|
||||
var hasMatchedCheckers = false;
|
||||
for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) {
|
||||
var eventSeq = this.mScenarios[scnIdx];
|
||||
|
||||
@ -516,9 +516,9 @@ function eventQueue(aEventType)
|
||||
var nextChecker = this.getNextExpectedEvent(eventSeq);
|
||||
if (nextChecker) {
|
||||
if (eventQueue.compareEvents(nextChecker, aEvent)) {
|
||||
matchedChecker = nextChecker;
|
||||
matchedChecker.wasCaught++;
|
||||
break;
|
||||
this.processMatchedChecker(aEvent, nextChecker, scnIdx, eventSeq.idx);
|
||||
hasMatchedCheckers = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,41 +526,46 @@ function eventQueue(aEventType)
|
||||
for (idx = 0; idx < eventSeq.length; idx++) {
|
||||
if (!eventSeq[idx].unexpected && eventSeq[idx].async) {
|
||||
if (eventQueue.compareEvents(eventSeq[idx], aEvent)) {
|
||||
matchedChecker = eventSeq[idx];
|
||||
matchedChecker.wasCaught++;
|
||||
this.processMatchedChecker(aEvent, eventSeq[idx], scnIdx, idx);
|
||||
hasMatchedCheckers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call 'check' functions on invoker's side.
|
||||
if (matchedChecker) {
|
||||
if ("check" in matchedChecker)
|
||||
matchedChecker.check(aEvent);
|
||||
|
||||
if (hasMatchedCheckers) {
|
||||
var invoker = this.getInvoker();
|
||||
if ("check" in invoker)
|
||||
invoker.check(aEvent);
|
||||
}
|
||||
|
||||
// Dump handled event.
|
||||
eventQueue.logEvent(aEvent, matchedChecker, this.areExpectedEventsLeft(),
|
||||
this.mNextInvokerStatus);
|
||||
|
||||
// If we don't have more events to wait then schedule next invoker.
|
||||
if (!this.areExpectedEventsLeft() &&
|
||||
if (this.hasMatchedScenario() &&
|
||||
(this.mNextInvokerStatus == kInvokerNotScheduled)) {
|
||||
this.processNextInvokerInTimeout();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have scheduled a next invoker then cancel in case of match.
|
||||
if ((this.mNextInvokerStatus == kInvokerPending) && matchedChecker)
|
||||
if ((this.mNextInvokerStatus == kInvokerPending) && hasMatchedCheckers)
|
||||
this.mNextInvokerStatus = kInvokerCanceled;
|
||||
}
|
||||
|
||||
// Helpers
|
||||
this.processMatchedChecker =
|
||||
function eventQueue_function(aEvent, aMatchedChecker, aScenarioIdx, aEventIdx)
|
||||
{
|
||||
aMatchedChecker.wasCaught++;
|
||||
|
||||
if ("check" in aMatchedChecker)
|
||||
aMatchedChecker.check(aEvent);
|
||||
|
||||
eventQueue.logEvent(aEvent, aMatchedChecker, aScenarioIdx, aEventIdx,
|
||||
this.areExpectedEventsLeft(),
|
||||
this.mNextInvokerStatus);
|
||||
}
|
||||
|
||||
this.getNextExpectedEvent =
|
||||
function eventQueue_getNextExpectedEvent(aEventSeq)
|
||||
{
|
||||
@ -636,6 +641,16 @@ function eventQueue(aEventType)
|
||||
return false;
|
||||
}
|
||||
|
||||
this.hasMatchedScenario =
|
||||
function eventQueue_hasMatchedScenario()
|
||||
{
|
||||
for (var scnIdx = 0; scnIdx < this.mScenarios.length; scnIdx++) {
|
||||
if (!this.areExpectedEventsLeft(this.mScenarios[scnIdx]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.getInvoker = function eventQueue_getInvoker()
|
||||
{
|
||||
return this.mInvokers[this.mIndex];
|
||||
@ -858,6 +873,7 @@ eventQueue.isSameEvent = function eventQueue_isSameEvent(aChecker, aEvent)
|
||||
}
|
||||
|
||||
eventQueue.logEvent = function eventQueue_logEvent(aOrigEvent, aMatchedChecker,
|
||||
aScenarioIdx, aEventIdx,
|
||||
aAreExpectedEventsLeft,
|
||||
aInvokerStatus)
|
||||
{
|
||||
@ -897,7 +913,8 @@ eventQueue.logEvent = function eventQueue_logEvent(aOrigEvent, aMatchedChecker,
|
||||
|
||||
var currType = eventQueue.getEventTypeAsString(aMatchedChecker);
|
||||
var currTargetDescr = eventQueue.getEventTargetDescr(aMatchedChecker);
|
||||
var consoleMsg = "*****\nEQ matched: " + currType + "\n*****";
|
||||
var consoleMsg = "*****\nScenario " + aScenarioIdx +
|
||||
", event " + aEventIdx + " matched: " + currType + "\n*****";
|
||||
gLogger.logToConsole(consoleMsg);
|
||||
|
||||
msg += " event, type: " + currType + ", target: " + currTargetDescr;
|
||||
@ -1727,7 +1744,8 @@ function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
|
||||
{
|
||||
if (aEvent instanceof nsIAccessibleStateChangeEvent) {
|
||||
var scEvent = aEvent.QueryInterface(nsIAccessibleStateChangeEvent);
|
||||
return aEvent.accessible = this.target && scEvent.state == aState;
|
||||
return (aEvent.accessible == getAccessible(this.target)) &&
|
||||
(scEvent.state == aState);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1771,6 +1789,59 @@ function expandedStateChecker(aIsEnabled, aTargetOrFunc, aTargetFuncArg)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Event sequances (array of predefined checkers)
|
||||
|
||||
/**
|
||||
* Event seq for single selection change.
|
||||
*/
|
||||
function selChangeSeq(aUnselectedID, aSelectedID)
|
||||
{
|
||||
if (!aUnselectedID) {
|
||||
return [
|
||||
new stateChangeChecker(STATE_SELECTED, false, true, aSelectedID),
|
||||
new invokerChecker(EVENT_SELECTION, aSelectedID)
|
||||
];
|
||||
}
|
||||
|
||||
// Return two possible scenarios: depending on widget type when selection is
|
||||
// moved the the order of items that get selected and unselected may vary.
|
||||
return [
|
||||
[
|
||||
new stateChangeChecker(STATE_SELECTED, false, false, aUnselectedID),
|
||||
new stateChangeChecker(STATE_SELECTED, false, true, aSelectedID),
|
||||
new invokerChecker(EVENT_SELECTION, aSelectedID)
|
||||
],
|
||||
[
|
||||
new stateChangeChecker(STATE_SELECTED, false, true, aSelectedID),
|
||||
new stateChangeChecker(STATE_SELECTED, false, false, aUnselectedID),
|
||||
new invokerChecker(EVENT_SELECTION, aSelectedID)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Event seq for item removed form the selection.
|
||||
*/
|
||||
function selRemoveSeq(aUnselectedID)
|
||||
{
|
||||
return [
|
||||
new stateChangeChecker(STATE_SELECTED, false, false, aUnselectedID),
|
||||
new invokerChecker(EVENT_SELECTION_REMOVE, aUnselectedID)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Event seq for item added to the selection.
|
||||
*/
|
||||
function selAddSeq(aSelectedID)
|
||||
{
|
||||
return [
|
||||
new stateChangeChecker(STATE_SELECTED, false, true, aSelectedID),
|
||||
new invokerChecker(EVENT_SELECTION_ADD, aSelectedID)
|
||||
];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Private implementation details.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -2043,16 +2114,23 @@ function sequenceItem(aProcessor, aEventType, aTarget, aItemID)
|
||||
/**
|
||||
* Invoker base class for prepare an action.
|
||||
*/
|
||||
function synthAction(aNodeOrID, aCheckerOrEventSeq)
|
||||
function synthAction(aNodeOrID, aEventsObj)
|
||||
{
|
||||
this.DOMNode = getNode(aNodeOrID);
|
||||
|
||||
if (aCheckerOrEventSeq) {
|
||||
if (aCheckerOrEventSeq instanceof Array) {
|
||||
this.eventSeq = aCheckerOrEventSeq;
|
||||
if (aEventsObj) {
|
||||
var scenarios = null;
|
||||
if (aEventsObj instanceof Array) {
|
||||
if (aEventsObj[0] instanceof Array)
|
||||
scenarios = aEventsObj; // scenarios
|
||||
else
|
||||
scenarios = [ aEventsObj ]; // event sequance
|
||||
} else {
|
||||
this.eventSeq = [ aCheckerOrEventSeq ];
|
||||
scenarios = [ [ aEventsObj ] ]; // a single checker object
|
||||
}
|
||||
|
||||
for (var i = 0; i < scenarios.length; i++)
|
||||
defineScenario(this, scenarios[i]);
|
||||
}
|
||||
|
||||
this.getID = function synthAction_getID()
|
||||
|
@ -38,31 +38,31 @@
|
||||
gQueue.push(new synthClick("combobox",
|
||||
new invokerChecker(EVENT_FOCUS, "cb1_item1")));
|
||||
gQueue.push(new synthDownKey("cb1_item1",
|
||||
new invokerChecker(EVENT_SELECTION, "cb1_item2")));
|
||||
selChangeSeq("cb1_item1", "cb1_item2")));
|
||||
|
||||
// closed combobox
|
||||
gQueue.push(new synthEscapeKey("combobox",
|
||||
new invokerChecker(EVENT_FOCUS, "combobox")));
|
||||
gQueue.push(new synthDownKey("cb1_item2",
|
||||
new invokerChecker(EVENT_SELECTION, "cb1_item3")));
|
||||
selChangeSeq("cb1_item2", "cb1_item3")));
|
||||
|
||||
// listbox
|
||||
gQueue.push(new synthClick("lb1_item1",
|
||||
new invokerChecker(EVENT_SELECTION, "lb1_item1")));
|
||||
gQueue.push(new synthDownKey("lb1_item1",
|
||||
new invokerChecker(EVENT_SELECTION, "lb1_item2")));
|
||||
selChangeSeq("lb1_item1", "lb1_item2")));
|
||||
|
||||
// multiselectable listbox
|
||||
gQueue.push(new synthClick("lb2_item1",
|
||||
new invokerChecker(EVENT_SELECTION, "lb2_item1")));
|
||||
selChangeSeq(null, "lb2_item1")));
|
||||
gQueue.push(new synthDownKey("lb2_item1",
|
||||
new invokerChecker(EVENT_SELECTION_ADD, "lb2_item2"),
|
||||
selAddSeq("lb2_item2"),
|
||||
{ shiftKey: true }));
|
||||
gQueue.push(new synthUpKey("lb2_item2",
|
||||
new invokerChecker(EVENT_SELECTION_REMOVE, "lb2_item2"),
|
||||
selRemoveSeq("lb2_item2"),
|
||||
{ shiftKey: true }));
|
||||
gQueue.push(new synthKey("lb2_item1", " ", { ctrlKey: true },
|
||||
new invokerChecker(EVENT_SELECTION_REMOVE, "lb2_item1")));
|
||||
selRemoveSeq("lb2_item1")));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
@ -77,7 +77,12 @@
|
||||
<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
|
||||
Bug 414302
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=810268"
|
||||
title="There's no way to know unselected item when selection in single selection was changed">
|
||||
Bug 810268
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
|
@ -36,7 +36,7 @@
|
||||
this.invoke = function selectItem_invoke() {
|
||||
var itemNode = this.selectNode.querySelector("*[aria-selected='true']");
|
||||
if (itemNode)
|
||||
itemNode.removeAttribute("aria-selected", "true");
|
||||
itemNode.removeAttribute("aria-selected");
|
||||
|
||||
this.itemNode.setAttribute("aria-selected", "true");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user