Bug 452710 - TakeFocus don't work on linkable accessibles, r=MarcoZ

This commit is contained in:
Alexander Surkov 2008-09-01 09:52:40 +08:00
parent 4be6cb573a
commit 7d7dd0225e
4 changed files with 246 additions and 23 deletions

View File

@ -118,7 +118,7 @@ nsLinkableAccessible::TakeFocus()
if (actionAcc)
return actionAcc->TakeFocus();
return NS_OK;
return nsHyperTextAccessibleWrap::TakeFocus();
}
NS_IMETHODIMP

View File

@ -64,6 +64,7 @@ _TEST_FILES =\
test_nsIAccessible_actions.xul \
test_nsIAccessible_name.html \
test_nsIAccessible_name.xul \
test_nsIAccessible_focus.html \
test_nsIAccessibleDocument.html \
test_nsIAccessibleEditableText.html \
test_nsIAccessibleHyperLink.html \

View File

@ -31,7 +31,7 @@ const nsIObserverService = Components.interfaces.nsIObserverService;
const nsIDOMNode = Components.interfaces.nsIDOMNode;
////////////////////////////////////////////////////////////////////////////////
// General
// Accessible general
/**
* nsIAccessibleRetrieval, initialized when test is loaded.
@ -41,22 +41,27 @@ var gAccRetrieval = null;
/**
* Return accessible for the given ID attribute or DOM element.
*
* @param aElmOrID [in] the ID attribute or DOM element to get an accessible
* for
* @param aInterfaces [in, optional] the accessible interface or the array of
* accessible interfaces to query it/them from obtained
* accessible
* @param aElmObj [out, optional] object to store DOM element which
* accessible is created for
* @param aAccOrElmOrID [in] DOM element or ID attribute to get an accessible
* for or an accessible to query additional interfaces.
* @param aInterfaces [in, optional] the accessible interface or the array of
* accessible interfaces to query it/them from obtained
* accessible
* @param aElmObj [out, optional] object to store DOM element which
* accessible is obtained for
*/
function getAccessible(aElmOrID, aInterfaces, aElmObj)
function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj)
{
var elm = null;
if (aElmOrID instanceof nsIDOMNode) {
elm = aElmOrID;
if (aAccOrElmOrID instanceof nsIAccessible) {
aAccOrElmOrID.QueryInterface(nsIAccessNode);
elm = aAccOrElmOrID.DOMNode;
} else if (aAccOrElmOrID instanceof nsIDOMNode) {
elm = aAccOrElmOrID;
} else {
var elm = document.getElementById(aElmOrID);
var elm = document.getElementById(aAccOrElmOrID);
if (!elm) {
ok(false, "Can't get DOM element for " + aID);
return null;
@ -66,15 +71,17 @@ function getAccessible(aElmOrID, aInterfaces, aElmObj)
if (aElmObj && (typeof aElmObj == "object"))
aElmObj.value = elm;
var acc = null;
try {
acc = gAccRetrieval.getAccessibleFor(elm);
} catch (e) {
}
var acc = (aAccOrElmOrID instanceof nsIAccessible) ? aAccOrElmOrID : null;
if (!acc) {
ok(false, "Can't get accessible for " + aID);
return null;
try {
acc = gAccRetrieval.getAccessibleFor(elm);
} catch (e) {
}
if (!acc) {
ok(false, "Can't get accessible for " + aID);
return null;
}
}
if (!aInterfaces)
@ -102,17 +109,98 @@ function getAccessible(aElmOrID, aInterfaces, aElmObj)
return acc;
}
////////////////////////////////////////////////////////////////////////////////
// Accessible Events
/**
* Register accessibility event listener.
*
* @param aEventType the accessible event type (see nsIAccessibleEvent for
* available constants).
* @param aEventHandler event listener object, when accessible event of the
* given type is handled then 'handleEvent' method of
* this object is invoked with nsIAccessibleEvent object
* as the first argument.
*/
function registerA11yEventListener(aEventType, aEventHandler)
{
if (!gA11yEventListenersCount) {
gObserverService = Components.classes["@mozilla.org/observer-service;1"].
getService(nsIObserverService);
gObserverService.addObserver(gA11yEventObserver, "accessible-event",
false);
}
if (!(aEventType in gA11yEventListeners))
gA11yEventListeners[aEventType] = new Array();
gA11yEventListeners[aEventType].push(aEventHandler);
gA11yEventListenersCount++;
}
/**
* Unregister accessibility event listener. Must be called for every registered
* event listener (see registerA11yEventListener() function) when it's not
* needed.
*/
function unregisterA11yEventListener(aEventType, aEventHandler)
{
var listenersArray = gA11yEventListeners[aEventType];
if (listenersArray) {
var index = listenersArray.indexOf(aEventHandler);
listenersArray.splice(index, 1);
if (!listenersArray.length) {
gA11yEventListeners[aEventType] = null;
delete gA11yEventListeners[aEventType];
}
}
gA11yEventListenersCount--;
if (!gA11yEventListenersCount) {
gObserverService.removeObserver(gA11yEventObserver,
"accessible-event");
}
}
////////////////////////////////////////////////////////////////////////////////
// Private
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// General
// Accessible general
function initialize()
{
gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
getService(nsIAccessibleRetrieval);
getService(nsIAccessibleRetrieval);
}
addLoadEvent(initialize);
////////////////////////////////////////////////////////////////////////////////
// Accessible Events
var gObserverService = null;
var gA11yEventListeners = {};
var gA11yEventListenersCount = 0;
var gA11yEventObserver =
{
observe: function observe(aSubject, aTopic, aData)
{
if (aTopic != "accessible-event")
return;
var event = aSubject.QueryInterface(nsIAccessibleEvent);
var listenersArray = gA11yEventListeners[event.eventType];
if (!listenersArray)
return;
for (var index = 0; index < listenersArray.length; index++)
listenersArray[index].handleEvent(event);
}
};

View File

@ -0,0 +1,134 @@
<html>
<head>
<title>nsIAccessible::takeFocus 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/a11y/accessible/common.js"></script>
<script type="application/javascript">
////////////////////////////////////////////////////////////////////////////
// Test
function doTest()
{
// focus ARIA link
var ID = "aria-link";
var linkAcc = getAccessible(ID);
gFocusManager.listenElement(linkAcc, ID, doTest2);
linkAcc.takeFocus();
}
function doTest2()
{
// focus first child of ARIA link
var ID = "aria-link2";
var linkAcc = getAccessible(ID);
gFocusManager.listenElement(linkAcc, ID, doTest3);
linkAcc.firstChild.takeFocus();
}
function doTest3()
{
// focus html:a
var ID = "link";
var linkAcc = getAccessible(ID);
gFocusManager.listenElement(linkAcc, ID, finishTest);
linkAcc.takeFocus();
}
function finishTest()
{
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
////////////////////////////////////////////////////////////////////////////
// Helpers
var gFocusManager =
{
// Public
listenElement: function listenElement(aAccOrID, aPrettyName, aCallback)
{
registerA11yEventListener(nsIAccessibleEvent.EVENT_FOCUS, this);
var elmObj = {};
this.mAcc = getAccessible(aAccOrID, null, elmObj);
this.mElm = elmObj.value;
this.mName = aPrettyName ? aPrettyName : aAccOrID;
this.mCallback = aCallback;
window.setTimeout(
function(aFocusMgr)
{
aFocusMgr.checkWasFocusHandled();
}, 0, this);
},
// Private
handleEvent: function handleEvent(aAccEvent)
{
var node = aAccEvent.DOMNode;
if (node == this.mElm)
this.mIsFocusHandled = true;
},
checkWasFocusHandled: function checkWasFocusHandled()
{
window.setTimeout(
function(aFocusMgr)
{
unregisterA11yEventListener(nsIAccessibleEvent.EVENT_FOCUS, this);
ok(aFocusMgr.mIsFocusHandled,
"Focus wasn't recieved for element with ID " + aFocusMgr.mName + ".");
var states = {}, extraStates = {};
aFocusMgr.mAcc.getFinalState(states, extraStates);
ok(states.value & nsIAccessibleStates.STATE_FOCUSED,
"No focused state for element with ID " + aFocusMgr.mName + ".");
aFocusMgr.mCallback();
}, 0, this);
},
mAcc: null,
mElm: null,
mName: "",
mIsFocusHandled: false
};
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=452710"
title="nsIAccessible::takeFocus testing">
Mozilla Bug 452710
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<span id="aria-link" role="link" tabindex="0">link</span>
<span id="aria-link2" role="link" tabindex="0">link</span>
<a id="link" href="">link</span>
</body>
</html>