зеркало из https://github.com/mozilla/gecko-dev.git
Bug 615189 - clean up FireAccessibleFocusEvent, r=fer, a=davidb
This commit is contained in:
Родитель
4a403e1281
Коммит
d5f44d3067
|
@ -1160,9 +1160,10 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
|||
// to the element with the id that activedescendant points to
|
||||
nsCOMPtr<nsINode> focusedNode = GetCurrentFocus();
|
||||
if (nsCoreUtils::GetRoleContent(focusedNode) == aContent) {
|
||||
nsAccessible* focusedAcc = GetAccService()->GetAccessible(focusedNode);
|
||||
nsRefPtr<nsRootAccessible> rootAcc = GetRootAccessible();
|
||||
if (rootAcc) {
|
||||
rootAcc->FireAccessibleFocusEvent(nsnull, focusedNode, nsnull, PR_TRUE);
|
||||
if (rootAcc && focusedAcc) {
|
||||
rootAcc->FireAccessibleFocusEvent(focusedAcc, nsnull, PR_TRUE);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -314,83 +314,56 @@ nsRootAccessible::GetCaretAccessible()
|
|||
return mCaretAccessible;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsRootAccessible::FireAccessibleFocusEvent(nsAccessible *aAccessible,
|
||||
nsINode *aNode,
|
||||
nsIDOMEvent *aFocusEvent,
|
||||
void
|
||||
nsRootAccessible::FireAccessibleFocusEvent(nsAccessible* aFocusAccessible,
|
||||
nsIContent* aRealFocusContent,
|
||||
PRBool aForceEvent,
|
||||
EIsFromUserInput aIsFromUserInput)
|
||||
{
|
||||
// Implementors: only fire delayed/async events from this method.
|
||||
|
||||
if (mCaretAccessible) {
|
||||
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aFocusEvent));
|
||||
if (nsevent) {
|
||||
// Use the originally focused node where the selection lives.
|
||||
// For example, use the anonymous HTML:input instead of the containing
|
||||
// XUL:textbox. In this case, sometimes it is a later focus event
|
||||
// which points to the actual anonymous child with focus, so to be safe
|
||||
// we need to reset the selection listener every time.
|
||||
// This happens because when some bindings handle focus, they retarget
|
||||
// focus to the appropriate child inside of themselves, but DOM focus
|
||||
// stays outside on that binding parent.
|
||||
nsCOMPtr<nsIDOMEventTarget> domEventTarget;
|
||||
nsevent->GetOriginalTarget(getter_AddRefs(domEventTarget));
|
||||
nsCOMPtr<nsIContent> realFocusedNode(do_QueryInterface(domEventTarget));
|
||||
if (!realFocusedNode) {
|
||||
// When FireCurrentFocusEvent() synthesizes a focus event,
|
||||
// the orignal target does not exist, so use the passed-in node
|
||||
// which is the relevant focused node
|
||||
realFocusedNode = do_QueryInterface(aNode);
|
||||
}
|
||||
if (realFocusedNode) {
|
||||
mCaretAccessible->SetControlSelectionListener(realFocusedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set selection listener for focused element.
|
||||
if (mCaretAccessible && aRealFocusContent)
|
||||
mCaretAccessible->SetControlSelectionListener(aRealFocusContent);
|
||||
|
||||
// Check for aria-activedescendant, which changes which element has focus
|
||||
nsINode *finalFocusNode = aNode;
|
||||
nsAccessible *finalFocusAccessible = aAccessible;
|
||||
nsAccessible* focusAccessible = aFocusAccessible;
|
||||
|
||||
nsIContent *finalFocusContent = nsCoreUtils::GetRoleContent(finalFocusNode);
|
||||
if (finalFocusContent) {
|
||||
nsAutoString id;
|
||||
if (finalFocusContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant, id)) {
|
||||
nsIDocument *doc = aNode->GetOwnerDoc();
|
||||
finalFocusNode = doc->GetElementById(id);
|
||||
if (!finalFocusNode) {
|
||||
// If aria-activedescendant is set to nonexistant ID, then treat as focus
|
||||
// on the activedescendant container (which has real DOM focus)
|
||||
finalFocusNode = aNode;
|
||||
}
|
||||
finalFocusAccessible = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
// Fire focus only if it changes, but always fire focus events when aForceEvent == PR_TRUE
|
||||
if (gLastFocusedNode == finalFocusNode && !aForceEvent) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!finalFocusAccessible) {
|
||||
finalFocusAccessible = GetAccService()->GetAccessible(finalFocusNode);
|
||||
// Check for aria-activedescendant, which changes which element has focus.
|
||||
// For activedescendant, the ARIA spec does not require that the user agent
|
||||
// checks whether finalFocusNode is actually a DOM descendant of the element
|
||||
// checks whether pointed node is actually a DOM descendant of the element
|
||||
// with the aria-activedescendant attribute.
|
||||
if (!finalFocusAccessible) {
|
||||
return PR_FALSE;
|
||||
nsIContent* content = focusAccessible->GetContent();
|
||||
if (content) {
|
||||
nsAutoString id;
|
||||
if (content->GetAttr(kNameSpaceID_None,
|
||||
nsAccessibilityAtoms::aria_activedescendant, id)) {
|
||||
nsIDocument* DOMDoc = content->GetOwnerDoc();
|
||||
nsIContent* activeDescendantContent = DOMDoc->GetElementById(id);
|
||||
|
||||
// If aria-activedescendant is set to nonexistant ID, then treat as focus
|
||||
// on the activedescendant container (which has real DOM focus).
|
||||
if (activeDescendantContent) {
|
||||
focusAccessible =
|
||||
GetAccService()->GetAccessible(activeDescendantContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gLastFocusedAccessiblesState = nsAccUtils::State(finalFocusAccessible);
|
||||
PRUint32 role = finalFocusAccessible->Role();
|
||||
if (role == nsIAccessibleRole::ROLE_MENUITEM) {
|
||||
if (!mCurrentARIAMenubar) { // Entering menus
|
||||
// The natural role is the role that this type of element normally has
|
||||
if (role != finalFocusAccessible->NativeRole()) { // Must be a DHTML menuitem
|
||||
nsAccessible *menuBarAccessible =
|
||||
nsAccUtils::GetAncestorWithRole(finalFocusAccessible,
|
||||
// Fire focus only if it changes, but always fire focus events when
|
||||
// aForceEvent == PR_TRUE
|
||||
nsINode* focusNode = focusAccessible->GetNode();
|
||||
if (gLastFocusedNode == focusNode && !aForceEvent)
|
||||
return;
|
||||
|
||||
gLastFocusedAccessiblesState = nsAccUtils::State(focusAccessible);
|
||||
|
||||
// Fire menu start/end events for ARIA menus.
|
||||
if (focusAccessible->ARIARole() == nsIAccessibleRole::ROLE_MENUITEM) {
|
||||
// The focus is inside a menu.
|
||||
if (!mCurrentARIAMenubar) {
|
||||
// Entering ARIA menu. Fire menu start event.
|
||||
nsAccessible* menuBarAccessible =
|
||||
nsAccUtils::GetAncestorWithRole(focusAccessible,
|
||||
nsIAccessibleRole::ROLE_MENUBAR);
|
||||
if (menuBarAccessible) {
|
||||
mCurrentARIAMenubar = menuBarAccessible->GetNode();
|
||||
|
@ -399,15 +372,14 @@ nsRootAccessible::FireAccessibleFocusEvent(nsAccessible *aAccessible,
|
|||
new AccEvent(nsIAccessibleEvent::EVENT_MENU_START,
|
||||
menuBarAccessible, aIsFromUserInput,
|
||||
AccEvent::eAllowDupes);
|
||||
if (menuStartEvent) {
|
||||
if (menuStartEvent)
|
||||
FireDelayedAccessibleEvent(menuStartEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mCurrentARIAMenubar) {
|
||||
// Focus left a menu. Fire menu end event.
|
||||
nsRefPtr<AccEvent> menuEndEvent =
|
||||
new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar,
|
||||
aIsFromUserInput, AccEvent::eAllowDupes);
|
||||
|
@ -417,29 +389,15 @@ nsRootAccessible::FireAccessibleFocusEvent(nsAccessible *aAccessible,
|
|||
mCurrentARIAMenubar = nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> focusContent = do_QueryInterface(finalFocusNode);
|
||||
nsIFrame *focusFrame = nsnull;
|
||||
if (focusContent) {
|
||||
nsIPresShell *shell = nsCoreUtils::GetPresShellFor(finalFocusNode);
|
||||
|
||||
NS_ASSERTION(shell, "No pres shell for final focus node!");
|
||||
if (!shell)
|
||||
return PR_FALSE;
|
||||
|
||||
focusFrame = focusContent->GetPrimaryFrame();
|
||||
}
|
||||
|
||||
NS_IF_RELEASE(gLastFocusedNode);
|
||||
gLastFocusedNode = finalFocusNode;
|
||||
gLastFocusedNode = focusNode;
|
||||
NS_IF_ADDREF(gLastFocusedNode);
|
||||
|
||||
// Coalesce focus events from the same document, because DOM focus event might
|
||||
// be fired for the document node and then for the focused DOM element.
|
||||
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_FOCUS,
|
||||
finalFocusNode, AccEvent::eCoalesceFromSameDocument,
|
||||
focusNode, AccEvent::eCoalesceFromSameDocument,
|
||||
aIsFromUserInput);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -545,7 +503,7 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
nsEventShell::FireEvent(accEvent);
|
||||
|
||||
if (isEnabled)
|
||||
FireAccessibleFocusEvent(accessible, targetNode, aEvent);
|
||||
FireAccessibleFocusEvent(accessible, targetContent);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -649,7 +607,7 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
}
|
||||
}
|
||||
}
|
||||
FireAccessibleFocusEvent(accessible, focusedItem, aEvent);
|
||||
FireAccessibleFocusEvent(accessible, targetContent);
|
||||
}
|
||||
else if (eventType.EqualsLiteral("blur")) {
|
||||
NS_IF_RELEASE(gLastFocusedNode);
|
||||
|
@ -720,7 +678,7 @@ nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
|||
}
|
||||
if (fireFocus) {
|
||||
// Always asynch, always from user input.
|
||||
FireAccessibleFocusEvent(accessible, targetNode, aEvent, PR_TRUE,
|
||||
FireAccessibleFocusEvent(accessible, targetContent, PR_TRUE,
|
||||
eFromUserInput);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,20 +91,28 @@ public:
|
|||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ROOTACCESSIBLE_IMPL_CID)
|
||||
|
||||
/**
|
||||
* Fire an accessible focus event for the current focusAccssible
|
||||
* and attach a new selection listener, if necessary.
|
||||
* Fire an accessible focus event for the focused accessible and attach a new
|
||||
* selection listener to real focused element, if necessary.
|
||||
*
|
||||
* @param aFocusAccessible [in] the accessible which has received focus
|
||||
* @param aFocusNode [in] the DOM node which has received focus
|
||||
* @param aFocusEvent [in] DOM focus event that caused
|
||||
* the node/accessible to receive focus
|
||||
* @param aForceEvent [in] fire a focus event even if the last focused
|
||||
* item was the same
|
||||
* @return boolean -- was a focus event actually fired
|
||||
* @param aRealFocusContent [in] the actual DOM element which has received
|
||||
* focus (see @note section)
|
||||
* @param aForceEvent [in, optional] fire a focus event even if
|
||||
* the last focused item was the same
|
||||
* @param aIsFromUserInput [in, optional] specifies whether the event is
|
||||
* from user input
|
||||
*
|
||||
* @note Use the originally focused node where the selection lives as real
|
||||
* focus node. For example, use the anonymous HTML:input instead of
|
||||
* the containing XUL:textbox. In this case, sometimes it is a later
|
||||
* focus event which points to the actual anonymous child with focus,
|
||||
* so to be safe we need to reset the selection listener every time.
|
||||
* This happens because when some bindings handle focus, they
|
||||
* retarget focus to the appropriate child inside of themselves, but
|
||||
* DOM focus stays outside on that binding parent.
|
||||
*/
|
||||
PRBool FireAccessibleFocusEvent(nsAccessible *aFocusAccessible,
|
||||
nsINode *aFocusNode,
|
||||
nsIDOMEvent *aFocusEvent,
|
||||
void FireAccessibleFocusEvent(nsAccessible* aFocusAccessible,
|
||||
nsIContent* aRealFocusContent,
|
||||
PRBool aForceEvent = PR_FALSE,
|
||||
EIsFromUserInput aIsFromUserInput = eAutoDetect);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче