mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 513213 - coalesce events when new event is appended to the queue, r=marcoz, ginn, davidb
This commit is contained in:
parent
0a322165de
commit
ad794d9985
@ -311,89 +311,89 @@ void
|
|||||||
nsAccEvent::ApplyEventRules(nsCOMArray<nsIAccessibleEvent> &aEventsToFire)
|
nsAccEvent::ApplyEventRules(nsCOMArray<nsIAccessibleEvent> &aEventsToFire)
|
||||||
{
|
{
|
||||||
PRUint32 numQueuedEvents = aEventsToFire.Count();
|
PRUint32 numQueuedEvents = aEventsToFire.Count();
|
||||||
for (PRInt32 tail = numQueuedEvents - 1; tail >= 0; tail --) {
|
PRInt32 tail = numQueuedEvents - 1;
|
||||||
nsRefPtr<nsAccEvent> tailEvent = GetAccEventPtr(aEventsToFire[tail]);
|
|
||||||
switch(tailEvent->mEventRule) {
|
|
||||||
case nsAccEvent::eCoalesceFromSameSubtree:
|
|
||||||
{
|
|
||||||
for (PRInt32 index = 0; index < tail; index ++) {
|
|
||||||
nsRefPtr<nsAccEvent> thisEvent = GetAccEventPtr(aEventsToFire[index]);
|
|
||||||
if (thisEvent->mEventType != tailEvent->mEventType)
|
|
||||||
continue; // Different type
|
|
||||||
|
|
||||||
if (thisEvent->mEventRule == nsAccEvent::eAllowDupes ||
|
nsRefPtr<nsAccEvent> tailEvent = GetAccEventPtr(aEventsToFire[tail]);
|
||||||
thisEvent->mEventRule == nsAccEvent::eDoNotEmit)
|
switch(tailEvent->mEventRule) {
|
||||||
continue; // Do not need to check
|
case nsAccEvent::eCoalesceFromSameSubtree:
|
||||||
|
{
|
||||||
|
for (PRInt32 index = 0; index < tail; index ++) {
|
||||||
|
nsRefPtr<nsAccEvent> thisEvent = GetAccEventPtr(aEventsToFire[index]);
|
||||||
|
if (thisEvent->mEventType != tailEvent->mEventType)
|
||||||
|
continue; // Different type
|
||||||
|
|
||||||
if (thisEvent->mDOMNode == tailEvent->mDOMNode) {
|
if (thisEvent->mEventRule == nsAccEvent::eAllowDupes ||
|
||||||
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
thisEvent->mEventRule == nsAccEvent::eDoNotEmit)
|
||||||
CoalesceReorderEventsFromSameSource(thisEvent, tailEvent);
|
continue; // Do not need to check
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dupe
|
if (thisEvent->mDOMNode == tailEvent->mDOMNode) {
|
||||||
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||||
|
CoalesceReorderEventsFromSameSource(thisEvent, tailEvent);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (nsCoreUtils::IsAncestorOf(tailEvent->mDOMNode,
|
|
||||||
thisEvent->mDOMNode)) {
|
|
||||||
// thisDOMNode is a descendant of tailDOMNode
|
|
||||||
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
|
||||||
CoalesceReorderEventsFromSameTree(tailEvent, thisEvent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not emit thisEvent, also apply this result to sibling
|
// Dupe
|
||||||
// nodes of thisDOMNode.
|
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||||
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
continue;
|
||||||
ApplyToSiblings(aEventsToFire, 0, index, thisEvent->mEventType,
|
}
|
||||||
thisEvent->mDOMNode, nsAccEvent::eDoNotEmit);
|
if (nsCoreUtils::IsAncestorOf(tailEvent->mDOMNode,
|
||||||
|
thisEvent->mDOMNode)) {
|
||||||
|
// thisDOMNode is a descendant of tailDOMNode
|
||||||
|
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||||
|
CoalesceReorderEventsFromSameTree(tailEvent, thisEvent);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (nsCoreUtils::IsAncestorOf(thisEvent->mDOMNode,
|
|
||||||
tailEvent->mDOMNode)) {
|
|
||||||
// tailDOMNode is a descendant of thisDOMNode
|
|
||||||
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
|
||||||
CoalesceReorderEventsFromSameTree(thisEvent, tailEvent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not emit tailEvent, also apply this result to sibling
|
// Do not emit thisEvent, also apply this result to sibling
|
||||||
// nodes of tailDOMNode.
|
// nodes of thisDOMNode.
|
||||||
tailEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||||
ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
|
ApplyToSiblings(aEventsToFire, 0, index, thisEvent->mEventType,
|
||||||
tailEvent->mDOMNode, nsAccEvent::eDoNotEmit);
|
thisEvent->mDOMNode, nsAccEvent::eDoNotEmit);
|
||||||
break;
|
continue;
|
||||||
|
}
|
||||||
|
if (nsCoreUtils::IsAncestorOf(thisEvent->mDOMNode,
|
||||||
|
tailEvent->mDOMNode)) {
|
||||||
|
// tailDOMNode is a descendant of thisDOMNode
|
||||||
|
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||||
|
CoalesceReorderEventsFromSameTree(thisEvent, tailEvent);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} // for (index)
|
|
||||||
|
|
||||||
if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit) {
|
// Do not emit tailEvent, also apply this result to sibling
|
||||||
// Not in another event node's subtree, and no other event is in
|
// nodes of tailDOMNode.
|
||||||
// this event node's subtree.
|
tailEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||||
// This event should be emitted
|
|
||||||
// Apply this result to sibling nodes of tailDOMNode
|
|
||||||
ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
|
ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
|
||||||
tailEvent->mDOMNode, nsAccEvent::eAllowDupes);
|
tailEvent->mDOMNode, nsAccEvent::eDoNotEmit);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} break; // case eCoalesceFromSameSubtree
|
} // for (index)
|
||||||
|
|
||||||
case nsAccEvent::eRemoveDupes:
|
if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit) {
|
||||||
{
|
// Not in another event node's subtree, and no other event is in
|
||||||
// Check for repeat events.
|
// this event node's subtree.
|
||||||
for (PRInt32 index = 0; index < tail; index ++) {
|
// This event should be emitted
|
||||||
nsRefPtr<nsAccEvent> accEvent = GetAccEventPtr(aEventsToFire[index]);
|
// Apply this result to sibling nodes of tailDOMNode
|
||||||
if (accEvent->mEventType == tailEvent->mEventType &&
|
ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
|
||||||
accEvent->mEventRule == tailEvent->mEventRule &&
|
tailEvent->mDOMNode, nsAccEvent::eAllowDupes);
|
||||||
accEvent->mDOMNode == tailEvent->mDOMNode) {
|
}
|
||||||
accEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
} break; // case eCoalesceFromSameSubtree
|
||||||
}
|
|
||||||
|
case nsAccEvent::eRemoveDupes:
|
||||||
|
{
|
||||||
|
// Check for repeat events.
|
||||||
|
for (PRInt32 index = 0; index < tail; index ++) {
|
||||||
|
nsRefPtr<nsAccEvent> accEvent = GetAccEventPtr(aEventsToFire[index]);
|
||||||
|
if (accEvent->mEventType == tailEvent->mEventType &&
|
||||||
|
accEvent->mEventRule == tailEvent->mEventRule &&
|
||||||
|
accEvent->mDOMNode == tailEvent->mDOMNode) {
|
||||||
|
accEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||||
}
|
}
|
||||||
} break; // case eRemoveDupes
|
}
|
||||||
|
} break; // case eRemoveDupes
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break; // case eAllowDupes, eDoNotEmit
|
break; // case eAllowDupes, eDoNotEmit
|
||||||
} // switch
|
} // switch
|
||||||
} // for (tail)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
|
@ -1185,8 +1185,8 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
|
|||||||
aAttribute == nsAccessibilityAtoms::title ||
|
aAttribute == nsAccessibilityAtoms::title ||
|
||||||
aAttribute == nsAccessibilityAtoms::aria_label ||
|
aAttribute == nsAccessibilityAtoms::aria_label ||
|
||||||
aAttribute == nsAccessibilityAtoms::aria_labelledby) {
|
aAttribute == nsAccessibilityAtoms::aria_labelledby) {
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE,
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE,
|
||||||
targetNode);
|
targetNode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1208,21 +1208,21 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
|
|||||||
nsCOMPtr<nsIDOMNode> multiSelectDOMNode;
|
nsCOMPtr<nsIDOMNode> multiSelectDOMNode;
|
||||||
multiSelectAccessNode->GetDOMNode(getter_AddRefs(multiSelectDOMNode));
|
multiSelectAccessNode->GetDOMNode(getter_AddRefs(multiSelectDOMNode));
|
||||||
NS_ASSERTION(multiSelectDOMNode, "A new accessible without a DOM node!");
|
NS_ASSERTION(multiSelectDOMNode, "A new accessible without a DOM node!");
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
|
||||||
multiSelectDOMNode,
|
multiSelectDOMNode,
|
||||||
nsAccEvent::eAllowDupes);
|
nsAccEvent::eAllowDupes);
|
||||||
|
|
||||||
static nsIContent::AttrValuesArray strings[] =
|
static nsIContent::AttrValuesArray strings[] =
|
||||||
{&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
|
{&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
|
||||||
if (aContent->FindAttrValueIn(kNameSpaceID_None, aAttribute,
|
if (aContent->FindAttrValueIn(kNameSpaceID_None, aAttribute,
|
||||||
strings, eCaseMatters) >= 0) {
|
strings, eCaseMatters) >= 0) {
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_REMOVE,
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_REMOVE,
|
||||||
targetNode);
|
targetNode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_ADD,
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_ADD,
|
||||||
targetNode);
|
targetNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1340,7 +1340,8 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
|||||||
aContent->AttrValueIs(kNameSpaceID_None,
|
aContent->AttrValueIs(kNameSpaceID_None,
|
||||||
nsAccessibilityAtoms::aria_valuetext, nsAccessibilityAtoms::_empty,
|
nsAccessibilityAtoms::aria_valuetext, nsAccessibilityAtoms::_empty,
|
||||||
eCaseMatters)))) {
|
eCaseMatters)))) {
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, targetNode);
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
|
||||||
|
targetNode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1357,8 +1358,8 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
|||||||
// at least until native API comes up with a more meaningful event.
|
// at least until native API comes up with a more meaningful event.
|
||||||
if (aAttribute == nsAccessibilityAtoms::aria_grabbed ||
|
if (aAttribute == nsAccessibilityAtoms::aria_grabbed ||
|
||||||
aAttribute == nsAccessibilityAtoms::aria_dropeffect) {
|
aAttribute == nsAccessibilityAtoms::aria_dropeffect) {
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
|
||||||
targetNode);
|
targetNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1592,13 +1593,14 @@ nsDocAccessible::CreateTextChangeEventForNode(nsIAccessible *aContainerAccessibl
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsDocAccessible::FireDelayedToolkitEvent(PRUint32 aEvent,
|
nsresult
|
||||||
nsIDOMNode *aDOMNode,
|
nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType,
|
||||||
nsAccEvent::EEventRule aAllowDupes,
|
nsIDOMNode *aDOMNode,
|
||||||
PRBool aIsAsynch)
|
nsAccEvent::EEventRule aAllowDupes,
|
||||||
|
PRBool aIsAsynch)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIAccessibleEvent> event =
|
nsCOMPtr<nsIAccessibleEvent> event =
|
||||||
new nsAccEvent(aEvent, aDOMNode, aIsAsynch, aAllowDupes);
|
new nsAccEvent(aEventType, aDOMNode, aIsAsynch, aAllowDupes);
|
||||||
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
return FireDelayedAccessibleEvent(event);
|
return FireDelayedAccessibleEvent(event);
|
||||||
@ -1616,6 +1618,10 @@ nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mEventsToFire.AppendObject(aEvent);
|
mEventsToFire.AppendObject(aEvent);
|
||||||
|
|
||||||
|
// Filter events.
|
||||||
|
nsAccEvent::ApplyEventRules(mEventsToFire);
|
||||||
|
|
||||||
if (mEventsToFire.Count() == 1) {
|
if (mEventsToFire.Count() == 1) {
|
||||||
// This is be the first delayed event in queue, start timer
|
// This is be the first delayed event in queue, start timer
|
||||||
// so that event gets fired via FlushEventsCallback
|
// so that event gets fired via FlushEventsCallback
|
||||||
@ -1643,9 +1649,6 @@ nsDocAccessible::FlushPendingEvents()
|
|||||||
// visibility. We don't flush the display because we don't care about
|
// visibility. We don't flush the display because we don't care about
|
||||||
// painting. If no flush is necessary the method will simple return.
|
// painting. If no flush is necessary the method will simple return.
|
||||||
presShell->FlushPendingNotifications(Flush_Layout);
|
presShell->FlushPendingNotifications(Flush_Layout);
|
||||||
|
|
||||||
// filter events
|
|
||||||
nsAccEvent::ApplyEventRules(mEventsToFire);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PRUint32 index = 0; index < length; index ++) {
|
for (PRUint32 index = 0; index < length; index ++) {
|
||||||
@ -2105,17 +2108,17 @@ nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
|
|||||||
// nsIAccessibleStates::STATE_INVISIBLE for the event's accessible object.
|
// nsIAccessibleStates::STATE_INVISIBLE for the event's accessible object.
|
||||||
PRUint32 additionEvent = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_SHOW :
|
PRUint32 additionEvent = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_SHOW :
|
||||||
nsIAccessibleEvent::EVENT_DOM_CREATE;
|
nsIAccessibleEvent::EVENT_DOM_CREATE;
|
||||||
FireDelayedToolkitEvent(additionEvent, childNode,
|
FireDelayedAccessibleEvent(additionEvent, childNode,
|
||||||
nsAccEvent::eCoalesceFromSameSubtree,
|
nsAccEvent::eCoalesceFromSameSubtree,
|
||||||
isAsynch);
|
isAsynch);
|
||||||
|
|
||||||
// Check to see change occured in an ARIA menu, and fire
|
// Check to see change occured in an ARIA menu, and fire
|
||||||
// an EVENT_MENUPOPUP_START if it did.
|
// an EVENT_MENUPOPUP_START if it did.
|
||||||
nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(childNode);
|
nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(childNode);
|
||||||
if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_MENUPOPUP) {
|
if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_MENUPOPUP) {
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
|
||||||
childNode, nsAccEvent::eRemoveDupes,
|
childNode, nsAccEvent::eRemoveDupes,
|
||||||
isAsynch);
|
isAsynch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
|
// Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
|
||||||
@ -2123,8 +2126,8 @@ nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
|
|||||||
while (PR_TRUE) {
|
while (PR_TRUE) {
|
||||||
if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_ALERT) {
|
if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_ALERT) {
|
||||||
nsCOMPtr<nsIDOMNode> alertNode(do_QueryInterface(ancestor));
|
nsCOMPtr<nsIDOMNode> alertNode(do_QueryInterface(ancestor));
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode,
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode,
|
||||||
nsAccEvent::eRemoveDupes, isAsynch);
|
nsAccEvent::eRemoveDupes, isAsynch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ancestor = ancestor->GetParent();
|
ancestor = ancestor->GetParent();
|
||||||
|
@ -121,15 +121,15 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Non-virtual method to fire a delayed event after a 0 length timeout.
|
* Non-virtual method to fire a delayed event after a 0 length timeout.
|
||||||
*
|
*
|
||||||
* @param aEvent [in] the nsIAccessibleEvent event type
|
* @param aEventType [in] the nsIAccessibleEvent event type
|
||||||
* @param aDOMNode [in] DOM node the accesible event should be fired for
|
* @param aDOMNode [in] DOM node the accesible event should be fired for
|
||||||
* @param aAllowDupes [in] rule to process an event (see EEventRule constants)
|
* @param aAllowDupes [in] rule to process an event (see EEventRule constants)
|
||||||
* @param aIsAsynch [in] set to PR_TRUE if this is not being called from
|
* @param aIsAsynch [in] set to PR_TRUE if this is not being called from
|
||||||
* code synchronous with a DOM event
|
* code synchronous with a DOM event
|
||||||
*/
|
*/
|
||||||
nsresult FireDelayedToolkitEvent(PRUint32 aEvent, nsIDOMNode *aDOMNode,
|
nsresult FireDelayedAccessibleEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
|
||||||
nsAccEvent::EEventRule aAllowDupes = nsAccEvent::eRemoveDupes,
|
nsAccEvent::EEventRule aAllowDupes = nsAccEvent::eRemoveDupes,
|
||||||
PRBool aIsAsynch = PR_FALSE);
|
PRBool aIsAsynch = PR_FALSE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fire accessible event after timeout.
|
* Fire accessible event after timeout.
|
||||||
|
@ -396,7 +396,8 @@ void nsRootAccessible::TryFireEarlyLoadEvent(nsIDOMNode *aDocNode)
|
|||||||
NS_ASSERTION(rootContentTreeItem, "No root content tree item");
|
NS_ASSERTION(rootContentTreeItem, "No root content tree item");
|
||||||
if (rootContentTreeItem == treeItem) {
|
if (rootContentTreeItem == treeItem) {
|
||||||
// No frames or iframes, so we can fire the doc load finished event early
|
// No frames or iframes, so we can fire the doc load finished event early
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD, aDocNode);
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD,
|
||||||
|
aDocNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,9 +539,9 @@ PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_FOCUS,
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
|
||||||
finalFocusNode, nsAccEvent::eRemoveDupes,
|
finalFocusNode, nsAccEvent::eRemoveDupes,
|
||||||
aIsAsynch);
|
aIsAsynch);
|
||||||
|
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
@ -893,7 +894,8 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
|
|||||||
FireCurrentFocusEvent();
|
FireCurrentFocusEvent();
|
||||||
}
|
}
|
||||||
else if (eventType.EqualsLiteral("ValueChange")) {
|
else if (eventType.EqualsLiteral("ValueChange")) {
|
||||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aTargetNode, nsAccEvent::eRemoveDupes);
|
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
|
||||||
|
aTargetNode, nsAccEvent::eRemoveDupes);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
else if (eventType.EqualsLiteral("mouseover")) {
|
else if (eventType.EqualsLiteral("mouseover")) {
|
||||||
|
@ -98,6 +98,7 @@ _TEST_FILES =\
|
|||||||
test_events_draganddrop.html \
|
test_events_draganddrop.html \
|
||||||
test_events_focus.xul \
|
test_events_focus.xul \
|
||||||
test_events_mutation.html \
|
test_events_mutation.html \
|
||||||
|
test_events_mutation_coalesce.html \
|
||||||
test_events_tree.xul \
|
test_events_tree.xul \
|
||||||
test_events_valuechange.html \
|
test_events_valuechange.html \
|
||||||
test_groupattrs.xul \
|
test_groupattrs.xul \
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constants
|
// Constants
|
||||||
|
|
||||||
|
const EVENT_ASYNCH_HIDE = nsIAccessibleEvent.EVENT_ASYNCH_HIDE;
|
||||||
|
const EVENT_ASYNCH_SHOW = nsIAccessibleEvent.EVENT_ASYNCH_SHOW;
|
||||||
const EVENT_DOCUMENT_LOAD_COMPLETE =
|
const EVENT_DOCUMENT_LOAD_COMPLETE =
|
||||||
nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
|
nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
|
||||||
|
const EVENT_DOM_CREATE = nsIAccessibleEvent.EVENT_DOM_CREATE;
|
||||||
const EVENT_DOM_DESTROY = nsIAccessibleEvent.EVENT_DOM_DESTROY;
|
const EVENT_DOM_DESTROY = nsIAccessibleEvent.EVENT_DOM_DESTROY;
|
||||||
const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS;
|
const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS;
|
||||||
const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE;
|
const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE;
|
||||||
@ -123,15 +126,10 @@ function invokerChecker(aEventType, aTarget)
|
|||||||
* // (used in the case when invoker expects single event).
|
* // (used in the case when invoker expects single event).
|
||||||
* DOMNode getter: function() {},
|
* DOMNode getter: function() {},
|
||||||
*
|
*
|
||||||
* // Array of items defining events expected (or not expected, see
|
* // Array of checker objects defining expected events on invoker's action.
|
||||||
* // 'doNotExpectEvents' property) on invoker's action.
|
|
||||||
* //
|
* //
|
||||||
* // Every array item should be either
|
* // Checker object interface:
|
||||||
* // 1) an array consisted from two elements, the first element is DOM or
|
|
||||||
* // a11y event type, second element is event target (DOM node or
|
|
||||||
* // accessible).
|
|
||||||
* //
|
* //
|
||||||
* // 2) object (invoker's checker object) like
|
|
||||||
* // var checker = {
|
* // var checker = {
|
||||||
* // type getter: function() {}, // DOM or a11y event type
|
* // type getter: function() {}, // DOM or a11y event type
|
||||||
* // target getter: function() {}, // DOM node or accessible
|
* // target getter: function() {}, // DOM node or accessible
|
||||||
@ -141,9 +139,9 @@ function invokerChecker(aEventType, aTarget)
|
|||||||
* // };
|
* // };
|
||||||
* eventSeq getter() {},
|
* eventSeq getter() {},
|
||||||
*
|
*
|
||||||
* // [optional, used together with 'eventSeq'] Boolean indicates if events
|
* // Array of checker objects defining unexpected events on invoker's
|
||||||
* // specified by 'eventSeq' property shouldn't be triggerd by invoker.
|
* // action.
|
||||||
* doNotExpectEvents getter() {},
|
* unexpectedEventSeq getter() {},
|
||||||
*
|
*
|
||||||
* // The ID of invoker.
|
* // The ID of invoker.
|
||||||
* getID: function(){} // returns invoker ID
|
* getID: function(){} // returns invoker ID
|
||||||
@ -174,8 +172,7 @@ function eventQueue(aEventType)
|
|||||||
|
|
||||||
// XXX: Intermittent test_events_caretmove.html fails withouth timeout,
|
// XXX: Intermittent test_events_caretmove.html fails withouth timeout,
|
||||||
// see bug 474952.
|
// see bug 474952.
|
||||||
window.setTimeout(function(aQueue) { aQueue.processNextInvoker(); }, 500,
|
this.processNextInvokerInTimeout(true);
|
||||||
this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -198,15 +195,20 @@ function eventQueue(aEventType)
|
|||||||
|
|
||||||
var invoker = this.getInvoker();
|
var invoker = this.getInvoker();
|
||||||
if (invoker) {
|
if (invoker) {
|
||||||
|
if ("finalCheck" in invoker)
|
||||||
|
invoker.finalCheck();
|
||||||
|
|
||||||
if (invoker.wasCaught) {
|
if (invoker.wasCaught) {
|
||||||
for (var idx = 0; idx < invoker.wasCaught.length; idx++) {
|
for (var idx = 0; idx < invoker.wasCaught.length; idx++) {
|
||||||
var id = this.getEventID(idx);
|
var id = this.getEventID(idx);
|
||||||
var type = this.getEventType(idx);
|
var type = this.getEventType(idx);
|
||||||
|
var unexpected = this.mEventSeq[idx].unexpected;
|
||||||
|
|
||||||
var typeStr = (typeof type == "string") ?
|
var typeStr = (typeof type == "string") ?
|
||||||
type : gAccRetrieval.getStringEventType(type);
|
type : gAccRetrieval.getStringEventType(type);
|
||||||
|
|
||||||
var msg = "test with ID = '" + id + "' failed. ";
|
var msg = "test with ID = '" + id + "' failed. ";
|
||||||
if (invoker.doNotExpectEvents) {
|
if (unexpected) {
|
||||||
var wasCaught = invoker.wasCaught[idx];
|
var wasCaught = invoker.wasCaught[idx];
|
||||||
if (!testFailed)
|
if (!testFailed)
|
||||||
testFailed = wasCaught;
|
testFailed = wasCaught;
|
||||||
@ -256,11 +258,22 @@ function eventQueue(aEventType)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invoker.doNotExpectEvents) {
|
if (this.areAllEventsUnexpected())
|
||||||
// Check in timeout invoker didn't fire registered events.
|
this.processNextInvokerInTimeout(true);
|
||||||
window.setTimeout(function(aQueue) { aQueue.processNextInvoker(); }, 500,
|
}
|
||||||
this);
|
|
||||||
|
this.processNextInvokerInTimeout = function eventQueue_processNextInvokerInTimeout(aUncondProcess)
|
||||||
|
{
|
||||||
|
if (!aUncondProcess && this.areAllEventsExpected()) {
|
||||||
|
// We need delay to avoid events coalesce from different invokers.
|
||||||
|
var queue = this;
|
||||||
|
SimpleTest.executeSoon(function() { queue.processNextInvoker(); });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check in timeout invoker didn't fire registered events.
|
||||||
|
window.setTimeout(function(aQueue) { aQueue.processNextInvoker(); }, 500,
|
||||||
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -282,33 +295,38 @@ function eventQueue(aEventType)
|
|||||||
if ("debugCheck" in invoker)
|
if ("debugCheck" in invoker)
|
||||||
invoker.debugCheck(aEvent);
|
invoker.debugCheck(aEvent);
|
||||||
|
|
||||||
if (invoker.doNotExpectEvents) {
|
// Search through unexpected events to ensure no one of them was handled.
|
||||||
// Search through event sequence to ensure it doesn't contain handled
|
for (var idx = 0; idx < this.mEventSeq.length; idx++) {
|
||||||
// event.
|
if (this.mEventSeq[idx].unexpected && this.compareEvents(idx, aEvent))
|
||||||
for (var idx = 0; idx < this.mEventSeq.length; idx++) {
|
|
||||||
if (this.compareEvents(idx, aEvent))
|
|
||||||
invoker.wasCaught[idx] = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We wait for events in order specified by eventSeq variable.
|
|
||||||
var idx = this.mEventSeqIdx + 1;
|
|
||||||
|
|
||||||
var matched = this.compareEvents(idx, aEvent);
|
|
||||||
this.dumpEventToDOM(aEvent, idx, matched);
|
|
||||||
|
|
||||||
if (matched) {
|
|
||||||
this.checkEvent(idx, aEvent);
|
|
||||||
invoker.wasCaught[idx] = true;
|
invoker.wasCaught[idx] = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (idx == this.mEventSeq.length - 1) {
|
// Wait for next expected event in an order specified by event sequence.
|
||||||
// We need delay to avoid events coalesce from different invokers.
|
|
||||||
var queue = this;
|
|
||||||
SimpleTest.executeSoon(function() { queue.processNextInvoker(); });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.mEventSeqIdx = idx;
|
// Compute next expected event index.
|
||||||
|
for (var idx = this.mEventSeqIdx + 1;
|
||||||
|
idx < this.mEventSeq.length && this.mEventSeq[idx].unexpected; idx++);
|
||||||
|
|
||||||
|
if (idx == this.mEventSeq.length) {
|
||||||
|
// There is no expected events in the sequence.
|
||||||
|
this.processNextInvokerInTimeout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var matched = this.compareEvents(idx, aEvent);
|
||||||
|
this.dumpEventToDOM(aEvent, idx, matched);
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
this.checkEvent(idx, aEvent);
|
||||||
|
invoker.wasCaught[idx] = true;
|
||||||
|
|
||||||
|
// The last event is expected and was handled, proceed next invoker.
|
||||||
|
if (idx == this.mEventSeq.length - 1) {
|
||||||
|
this.processNextInvokerInTimeout();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.mEventSeqIdx = idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,12 +343,26 @@ function eventQueue(aEventType)
|
|||||||
|
|
||||||
this.setEventHandler = function eventQueue_setEventHandler(aInvoker)
|
this.setEventHandler = function eventQueue_setEventHandler(aInvoker)
|
||||||
{
|
{
|
||||||
|
// Create unique event sequence concatenating expected and unexpected
|
||||||
|
// events.
|
||||||
this.mEventSeq = ("eventSeq" in aInvoker) ?
|
this.mEventSeq = ("eventSeq" in aInvoker) ?
|
||||||
aInvoker.eventSeq :
|
aInvoker.eventSeq :
|
||||||
[ new invokerChecker(this.mDefEventType, aInvoker.DOMNode) ];
|
[ new invokerChecker(this.mDefEventType, aInvoker.DOMNode) ];
|
||||||
|
|
||||||
|
for (var idx = 0; idx < this.mEventSeq.length; idx++)
|
||||||
|
this.mEventSeq[idx].unexpected = false;
|
||||||
|
|
||||||
|
var unexpectedSeq = aInvoker.unexpectedEventSeq;
|
||||||
|
if (unexpectedSeq) {
|
||||||
|
for (var idx = 0; idx < unexpectedSeq.length; idx++)
|
||||||
|
unexpectedSeq[idx].unexpected = true;
|
||||||
|
|
||||||
|
this.mEventSeq = this.mEventSeq.concat(unexpectedSeq);
|
||||||
|
}
|
||||||
|
|
||||||
this.mEventSeqIdx = -1;
|
this.mEventSeqIdx = -1;
|
||||||
|
|
||||||
|
// Register event listeners
|
||||||
if (this.mEventSeq) {
|
if (this.mEventSeq) {
|
||||||
aInvoker.wasCaught = new Array(this.mEventSeq.length);
|
aInvoker.wasCaught = new Array(this.mEventSeq.length);
|
||||||
|
|
||||||
@ -390,6 +422,16 @@ function eventQueue(aEventType)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.getEventID = function eventQueue_getEventID(aIdx)
|
||||||
|
{
|
||||||
|
var eventItem = this.mEventSeq[aIdx];
|
||||||
|
if ("getID" in eventItem)
|
||||||
|
return eventItem.getID();
|
||||||
|
|
||||||
|
var invoker = this.getInvoker();
|
||||||
|
return invoker.getID();
|
||||||
|
}
|
||||||
|
|
||||||
this.compareEvents = function eventQueue_compareEvents(aIdx, aEvent)
|
this.compareEvents = function eventQueue_compareEvents(aIdx, aEvent)
|
||||||
{
|
{
|
||||||
var eventType1 = this.getEventType(aIdx);
|
var eventType1 = this.getEventType(aIdx);
|
||||||
@ -426,14 +468,24 @@ function eventQueue(aEventType)
|
|||||||
invoker.check(aEvent);
|
invoker.check(aEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getEventID = function eventQueue_getEventID(aIdx)
|
this.areAllEventsExpected = function eventQueue_areAllEventsExpected()
|
||||||
{
|
{
|
||||||
var eventItem = this.mEventSeq[aIdx];
|
for (var idx = 0; idx < this.mEventSeq.length; idx++) {
|
||||||
if ("getID" in eventItem)
|
if (this.mEventSeq[idx].unexpected)
|
||||||
return eventItem.getID();
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var invoker = this.getInvoker();
|
return true;
|
||||||
return invoker.getID();
|
}
|
||||||
|
|
||||||
|
this.areAllEventsUnexpected = function eventQueue_areAllEventsUnxpected()
|
||||||
|
{
|
||||||
|
for (var idx = 0; idx < this.mEventSeq.length; idx++) {
|
||||||
|
if (!this.mEventSeq[idx].unexpected)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dumpEventToDOM = function eventQueue_dumpEventToDOM(aOrigEvent,
|
this.dumpEventToDOM = function eventQueue_dumpEventToDOM(aOrigEvent,
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
this.DOMNode = getNode(aNodeOrID);
|
this.DOMNode = getNode(aNodeOrID);
|
||||||
this.doNotExpectEvents = aDoNotExpectEvents;
|
this.doNotExpectEvents = aDoNotExpectEvents;
|
||||||
this.eventSeq = [];
|
this.eventSeq = [];
|
||||||
|
this.unexpectedEventSeq = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change default target (aNodeOrID) registered for the given event type.
|
* Change default target (aNodeOrID) registered for the given event type.
|
||||||
@ -59,9 +60,9 @@
|
|||||||
this.setTarget = function mutateA11yTree_setTarget(aEventType, aTarget)
|
this.setTarget = function mutateA11yTree_setTarget(aEventType, aTarget)
|
||||||
{
|
{
|
||||||
var type = this.getA11yEventType(aEventType);
|
var type = this.getA11yEventType(aEventType);
|
||||||
for (var idx = 0; idx < this.eventSeq.length; idx++) {
|
for (var idx = 0; idx < this.getEventSeq().length; idx++) {
|
||||||
if (this.eventSeq[idx].type == type) {
|
if (this.getEventSeq()[idx].type == type) {
|
||||||
this.eventSeq[idx].target = aTarget;
|
this.getEventSeq()[idx].target = aTarget;
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +79,7 @@
|
|||||||
var type = this.getA11yEventType(aEventType);
|
var type = this.getA11yEventType(aEventType);
|
||||||
for (var i = 1; i < aTargets.length; i++) {
|
for (var i = 1; i < aTargets.length; i++) {
|
||||||
var checker = new invokerChecker(type, aTargets[i]);
|
var checker = new invokerChecker(type, aTargets[i]);
|
||||||
this.eventSeq.splice(++targetIdx, 0, checker);
|
this.getEventSeq().splice(++targetIdx, 0, checker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,24 +104,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.getEventSeq = function mutateA11yTree_getEventSeq()
|
||||||
|
{
|
||||||
|
return this.doNotExpectEvents ? this.unexpectedEventSeq : this.eventSeq;
|
||||||
|
}
|
||||||
|
|
||||||
this.mIsDOMChange = aIsDOMChange;
|
this.mIsDOMChange = aIsDOMChange;
|
||||||
|
|
||||||
if (aEventTypes & kHideEvent) {
|
if (aEventTypes & kHideEvent) {
|
||||||
var checker = new invokerChecker(this.getA11yEventType(kHideEvent),
|
var checker = new invokerChecker(this.getA11yEventType(kHideEvent),
|
||||||
this.DOMNode);
|
this.DOMNode);
|
||||||
this.eventSeq.push(checker);
|
this.getEventSeq().push(checker);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aEventTypes & kShowEvent) {
|
if (aEventTypes & kShowEvent) {
|
||||||
var checker = new invokerChecker(this.getA11yEventType(kShowEvent),
|
var checker = new invokerChecker(this.getA11yEventType(kShowEvent),
|
||||||
this.DOMNode);
|
this.DOMNode);
|
||||||
this.eventSeq.push(checker);
|
this.getEventSeq().push(checker);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aEventTypes & kReorderEvent) {
|
if (aEventTypes & kReorderEvent) {
|
||||||
var checker = new invokerChecker(this.getA11yEventType(kReorderEvent),
|
var checker = new invokerChecker(this.getA11yEventType(kReorderEvent),
|
||||||
this.DOMNode.parentNode);
|
this.DOMNode.parentNode);
|
||||||
this.eventSeq.push(checker);
|
this.getEventSeq().push(checker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
409
accessible/tests/mochitest/test_events_mutation_coalesce.html
Normal file
409
accessible/tests/mochitest/test_events_mutation_coalesce.html
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Accessible mutation events coalescence testing</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css"
|
||||||
|
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/a11y/accessible/events.js"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Invoker base classes
|
||||||
|
|
||||||
|
const kRemoveElm = 1;
|
||||||
|
const kHideElm = 2;
|
||||||
|
const kAddElm = 3;
|
||||||
|
const kShowElm = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class to test of mutation events coalescence.
|
||||||
|
*/
|
||||||
|
function coalescenceBase(aChildAction, aParentAction,
|
||||||
|
aPerformActionOnChildInTheFirstPlace,
|
||||||
|
aIsChildsToDo)
|
||||||
|
{
|
||||||
|
// Invoker interface
|
||||||
|
|
||||||
|
this.invoke = function coalescenceBase_invoke()
|
||||||
|
{
|
||||||
|
if (aPerformActionOnChildInTheFirstPlace) {
|
||||||
|
this.invokeAction(this.childNode, aChildAction);
|
||||||
|
this.invokeAction(this.parentNode, aParentAction);
|
||||||
|
} else {
|
||||||
|
this.invokeAction(this.parentNode, aParentAction);
|
||||||
|
this.invokeAction(this.childNode, aChildAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getID = function coalescenceBase_getID()
|
||||||
|
{
|
||||||
|
var childAction = this.getActionName(aChildAction) + " child";
|
||||||
|
var parentAction = this.getActionName(aParentAction) + " parent";
|
||||||
|
|
||||||
|
if (aPerformActionOnChildInTheFirstPlace)
|
||||||
|
return childAction + " and then " + parentAction;
|
||||||
|
|
||||||
|
return parentAction + " and then " + childAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.finalCheck = function coalescenceBase_check()
|
||||||
|
{
|
||||||
|
if (!aIsChildsToDo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
todo(false,
|
||||||
|
"Unexpected event " + this.getEventType(aChildAction) +
|
||||||
|
" for child in the test '" + this.getID() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation details
|
||||||
|
|
||||||
|
this.invokeAction = function coalescenceBase_invokeAction(aNode, aAction)
|
||||||
|
{
|
||||||
|
switch (aAction) {
|
||||||
|
case kRemoveElm:
|
||||||
|
aNode.parentNode.removeChild(aNode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kHideElm:
|
||||||
|
aNode.style.display = "none";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kAddElm:
|
||||||
|
if (aNode == this.parentNode)
|
||||||
|
this.hostNode.appendChild(this.parentNode);
|
||||||
|
else
|
||||||
|
this.parentNode.appendChild(this.childNode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kShowElm:
|
||||||
|
aNode.style.display = "block";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return INVOKER_ACTION_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getEventType = function coalescenceBase_getEventType(aAction)
|
||||||
|
{
|
||||||
|
switch (aAction) {
|
||||||
|
case kRemoveElm:
|
||||||
|
return EVENT_DOM_DESTROY;
|
||||||
|
case kHideElm:
|
||||||
|
return EVENT_ASYNCH_HIDE;
|
||||||
|
case kAddElm:
|
||||||
|
return EVENT_DOM_CREATE;
|
||||||
|
case kShowElm:
|
||||||
|
return EVENT_ASYNCH_SHOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getActionName = function coalescenceBase_getActionName(aAction)
|
||||||
|
{
|
||||||
|
switch (aAction) {
|
||||||
|
case kRemoveElm:
|
||||||
|
return "remove";
|
||||||
|
case kHideElm:
|
||||||
|
return "hide";
|
||||||
|
case kAddElm:
|
||||||
|
return "add";
|
||||||
|
case kShowElm:
|
||||||
|
return "show";
|
||||||
|
default:
|
||||||
|
return "??";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initSequence = function coalescenceBase_initSequence()
|
||||||
|
{
|
||||||
|
// expected events
|
||||||
|
var eventType = this.getEventType(aParentAction);
|
||||||
|
this.eventSeq = [
|
||||||
|
new invokerChecker(eventType, this.parentNode),
|
||||||
|
new invokerChecker(EVENT_REORDER, this.hostNode)
|
||||||
|
];
|
||||||
|
|
||||||
|
// unexpected events
|
||||||
|
this.unexpectedEventSeq = [
|
||||||
|
new invokerChecker(EVENT_REORDER, this.parentNode)
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!aIsChildsToDo) {
|
||||||
|
var eventType = this.getEventType(aChildAction);
|
||||||
|
var checker = new invokerChecker(eventType, this.childNode);
|
||||||
|
this.unexpectedEventSeq.unshift(checker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove or hide mutation events coalescence testing.
|
||||||
|
*/
|
||||||
|
function removeOrHidecoalescenceBase(aChildID, aParentID,
|
||||||
|
aChildAction, aParentAction,
|
||||||
|
aPerformActionOnChildInTheFirstPlace,
|
||||||
|
aIsChildsToDo)
|
||||||
|
{
|
||||||
|
this.__proto__ = new coalescenceBase(aChildAction, aParentAction,
|
||||||
|
aPerformActionOnChildInTheFirstPlace,
|
||||||
|
aIsChildsToDo);
|
||||||
|
|
||||||
|
this.init = function removeOrHidecoalescenceBase_init()
|
||||||
|
{
|
||||||
|
this.childNode = getNode(aChildID);
|
||||||
|
this.parentNode = getNode(aParentID);
|
||||||
|
this.hostNode = this.parentNode.parentNode;
|
||||||
|
|
||||||
|
// ensure child accessible is created
|
||||||
|
getAccessible(this.childNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initalization
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
this.initSequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Invokers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove child node and then its parent node from DOM tree.
|
||||||
|
*/
|
||||||
|
function removeChildNParent(aChildID, aParentID)
|
||||||
|
{
|
||||||
|
this.__proto__ = new removeOrHidecoalescenceBase(aChildID, aParentID,
|
||||||
|
kRemoveElm, kRemoveElm,
|
||||||
|
true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove parent node and then its child node from DOM tree.
|
||||||
|
*/
|
||||||
|
function removeParentNChild(aChildID, aParentID)
|
||||||
|
{
|
||||||
|
this.__proto__ = new removeOrHidecoalescenceBase(aChildID, aParentID,
|
||||||
|
kRemoveElm, kRemoveElm,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide child node and then its parent node.
|
||||||
|
*/
|
||||||
|
function hideChildNParent(aChildID, aParentID)
|
||||||
|
{
|
||||||
|
this.__proto__ = new removeOrHidecoalescenceBase(aChildID, aParentID,
|
||||||
|
kHideElm, kHideElm,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide parent node and then its child node.
|
||||||
|
*/
|
||||||
|
function hideParentNChild(aChildID, aParentID)
|
||||||
|
{
|
||||||
|
this.__proto__ = new removeOrHidecoalescenceBase(aChildID, aParentID,
|
||||||
|
kHideElm, kHideElm,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide child node and then remove its parent node.
|
||||||
|
*/
|
||||||
|
function hideChildNRemoveParent(aChildID, aParentID)
|
||||||
|
{
|
||||||
|
this.__proto__ = new removeOrHidecoalescenceBase(aChildID, aParentID,
|
||||||
|
kHideElm, kRemoveElm,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide parent node and then remove its child node.
|
||||||
|
*/
|
||||||
|
function hideParentNRemoveChild(aChildID, aParentID)
|
||||||
|
{
|
||||||
|
this.__proto__ = new removeOrHidecoalescenceBase(aChildID, aParentID,
|
||||||
|
kRemoveElm, kHideElm,
|
||||||
|
false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove child node and then hide its parent node.
|
||||||
|
*/
|
||||||
|
function removeChildNHideParent(aChildID, aParentID)
|
||||||
|
{
|
||||||
|
this.__proto__ = new removeOrHidecoalescenceBase(aChildID, aParentID,
|
||||||
|
kRemoveElm, kHideElm,
|
||||||
|
true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove parent node and then hide its child node.
|
||||||
|
*/
|
||||||
|
function removeParentNHideChild(aChildID, aParentID)
|
||||||
|
{
|
||||||
|
this.__proto__ = new removeOrHidecoalescenceBase(aChildID, aParentID,
|
||||||
|
kHideElm, kRemoveElm,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and append parent node and create and append child node to it.
|
||||||
|
*/
|
||||||
|
function addParentNChild(aHostID, aPerformActionOnChildInTheFirstPlace)
|
||||||
|
{
|
||||||
|
this.init = function addParentNChild_init()
|
||||||
|
{
|
||||||
|
this.hostNode = getNode(aHostID);
|
||||||
|
this.parentNode = document.createElement("select");
|
||||||
|
this.childNode = document.createElement("option");
|
||||||
|
this.childNode.textContent = "testing";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__proto__ = new coalescenceBase(kAddElm, kAddElm,
|
||||||
|
aPerformActionOnChildInTheFirstPlace);
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
this.initSequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show parent node and show child node to it.
|
||||||
|
*/
|
||||||
|
function showParentNChild(aParentID, aChildID,
|
||||||
|
aPerformActionOnChildInTheFirstPlace)
|
||||||
|
{
|
||||||
|
this.init = function showParentNChild_init()
|
||||||
|
{
|
||||||
|
this.parentNode = getNode(aParentID);
|
||||||
|
this.hostNode = this.parentNode.parentNode;
|
||||||
|
this.childNode = getNode(aChildID);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__proto__ = new coalescenceBase(kShowElm, kShowElm,
|
||||||
|
aPerformActionOnChildInTheFirstPlace);
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
this.initSequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and append child node to the DOM and then show parent node.
|
||||||
|
*/
|
||||||
|
function showParentNAddChild(aParentID,
|
||||||
|
aPerformActionOnChildInTheFirstPlace)
|
||||||
|
{
|
||||||
|
this.init = function showParentNAddChild_init()
|
||||||
|
{
|
||||||
|
this.parentNode = getNode(aParentID);
|
||||||
|
this.hostNode = this.parentNode.parentNode;
|
||||||
|
this.childNode = document.createElement("option");
|
||||||
|
this.childNode.textContent = "testing";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__proto__ = new coalescenceBase(kAddElm, kShowElm,
|
||||||
|
aPerformActionOnChildInTheFirstPlace,
|
||||||
|
true);
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
this.initSequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Do tests.
|
||||||
|
|
||||||
|
var gQueue = null;
|
||||||
|
// var gA11yEventDumpID = "eventdump"; // debug stuff
|
||||||
|
|
||||||
|
function doTests()
|
||||||
|
{
|
||||||
|
gQueue = new eventQueue();
|
||||||
|
|
||||||
|
gQueue.push(new removeChildNParent("option1", "select1"));
|
||||||
|
gQueue.push(new removeParentNChild("option2", "select2"));
|
||||||
|
gQueue.push(new hideChildNParent("option3", "select3"));
|
||||||
|
gQueue.push(new hideParentNChild("option4", "select4"));
|
||||||
|
gQueue.push(new hideChildNRemoveParent("option5", "select5"));
|
||||||
|
gQueue.push(new hideParentNRemoveChild("option6", "select6"));
|
||||||
|
gQueue.push(new removeChildNHideParent("option7", "select7"));
|
||||||
|
gQueue.push(new removeParentNHideChild("option8", "select8"));
|
||||||
|
|
||||||
|
gQueue.push(new addParentNChild("testContainer", false));
|
||||||
|
gQueue.push(new addParentNChild("testContainer", true));
|
||||||
|
gQueue.push(new showParentNChild("select9", "option9", false));
|
||||||
|
gQueue.push(new showParentNChild("select10", "option10", true));
|
||||||
|
gQueue.push(new showParentNAddChild("select11", false));
|
||||||
|
gQueue.push(new showParentNAddChild("select12", true));
|
||||||
|
|
||||||
|
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
addA11yLoadEvent(doTests);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://bugzilla.mozilla.org/show_bug.cgi?id=513213"
|
||||||
|
title="coalesce events when new event is appended to the queue">
|
||||||
|
Mozilla Bug 513213
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none"></div>
|
||||||
|
<pre id="test">
|
||||||
|
</pre>
|
||||||
|
<div id="eventdump"></div>
|
||||||
|
|
||||||
|
<div id="testContainer">
|
||||||
|
<select id="select1">
|
||||||
|
<option id="option1">option</option>
|
||||||
|
</select>
|
||||||
|
<select id="select2">
|
||||||
|
<option id="option2">option</option>
|
||||||
|
</select>
|
||||||
|
<select id="select3">
|
||||||
|
<option id="option3">option</option>
|
||||||
|
</select>
|
||||||
|
<select id="select4">
|
||||||
|
<option id="option4">option</option>
|
||||||
|
</select>
|
||||||
|
<select id="select5">
|
||||||
|
<option id="option5">option</option>
|
||||||
|
</select>
|
||||||
|
<select id="select6">
|
||||||
|
<option id="option6">option</option>
|
||||||
|
</select>
|
||||||
|
<select id="select7">
|
||||||
|
<option id="option7">option</option>
|
||||||
|
</select>
|
||||||
|
<select id="select8">
|
||||||
|
<option id="option8">option</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="select9" style="display: none">
|
||||||
|
<option id="option9" style="display: none">testing</option>
|
||||||
|
</select>
|
||||||
|
<select id="select10" style="display: none">
|
||||||
|
<option id="option10" style="display: none">testing</option>
|
||||||
|
</select>
|
||||||
|
<select id="select11" style="display: none"></select>
|
||||||
|
<select id="select12" style="display: none"></select>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user