Bug 787858 - XUL textbox context menu inaccessible, r=tbsaunde

This commit is contained in:
Alexander Surkov 2013-12-07 16:37:04 -05:00
parent 7dbc4de777
commit e18f2c52b6
23 changed files with 207 additions and 810 deletions

View File

@ -1310,7 +1310,7 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
accessible = new XULLabelAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:textbox")) {
accessible = new XULTextFieldAccessible(aContent, aDoc);
accessible = new EnumRoleAccessible(aContent, aDoc, roles::SECTION);
} else if (role.EqualsLiteral("xul:thumb")) {
accessible = new XULThumbAccessible(aContent, aDoc);

View File

@ -1052,56 +1052,37 @@ Accessible::TakeFocus()
return NS_OK;
}
ENameValueFlag
Accessible::GetHTMLName(nsString& aLabel)
void
Accessible::XULElmName(DocAccessible* aDocument,
nsIContent* aElm, nsString& aName)
{
Accessible* labelAcc = nullptr;
HTMLLabelIterator iter(Document(), this);
while ((labelAcc = iter.Next())) {
nsTextEquivUtils::AppendTextEquivFromContent(this, labelAcc->GetContent(),
&aLabel);
aLabel.CompressWhitespace();
}
/**
* 3 main cases for XUL Controls to be labeled
* 1 - control contains label="foo"
* 2 - control has, as a child, a label element
* - label has either value="foo" or children
* 3 - non-child label contains control="controlID"
* - label has either value="foo" or children
* Once a label is found, the search is discontinued, so a control
* that has a label child as well as having a label external to
* the control that uses the control="controlID" syntax will use
* the child label for its Name.
*/
if (!aLabel.IsEmpty())
return eNameOK;
nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
return aLabel.IsEmpty() ? eNameOK : eNameFromSubtree;
}
/**
* 3 main cases for XUL Controls to be labeled
* 1 - control contains label="foo"
* 2 - control has, as a child, a label element
* - label has either value="foo" or children
* 3 - non-child label contains control="controlID"
* - label has either value="foo" or children
* Once a label is found, the search is discontinued, so a control
* that has a label child as well as having a label external to
* the control that uses the control="controlID" syntax will use
* the child label for its Name.
*/
ENameValueFlag
Accessible::GetXULName(nsString& aName)
{
// CASE #1 (via label attribute) -- great majority of the cases
nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl =
do_QueryInterface(mContent);
nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl = do_QueryInterface(aElm);
if (labeledEl) {
labeledEl->GetLabel(aName);
} else {
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl =
do_QueryInterface(mContent);
nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl = do_QueryInterface(aElm);
if (itemEl) {
itemEl->GetLabel(aName);
} else {
nsCOMPtr<nsIDOMXULSelectControlElement> select =
do_QueryInterface(mContent);
nsCOMPtr<nsIDOMXULSelectControlElement> select = do_QueryInterface(aElm);
// Use label if this is not a select control element which
// uses label attribute to indicate which option is selected
if (!select) {
nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(mContent));
nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(aElm));
if (xulEl)
xulEl->GetAttribute(NS_LITERAL_STRING("label"), aName);
}
@ -1111,7 +1092,7 @@ Accessible::GetXULName(nsString& aName)
// CASES #2 and #3 ------ label as a child or <label control="id" ... > </label>
if (aName.IsEmpty()) {
Accessible* labelAcc = nullptr;
XULLabelIterator iter(Document(), mContent);
XULLabelIterator iter(aDocument, aElm);
while ((labelAcc = iter.Next())) {
nsCOMPtr<nsIDOMXULLabelElement> xulLabel =
do_QueryInterface(labelAcc->GetContent());
@ -1120,30 +1101,27 @@ Accessible::GetXULName(nsString& aName)
// If no value attribute, a non-empty label must contain
// children that define its text -- possibly using HTML
nsTextEquivUtils::
AppendTextEquivFromContent(this, labelAcc->GetContent(), &aName);
AppendTextEquivFromContent(labelAcc, labelAcc->GetContent(), &aName);
}
}
}
aName.CompressWhitespace();
if (!aName.IsEmpty())
return eNameOK;
return;
// Can get text from title of <toolbaritem> if we're a child of a <toolbaritem>
nsIContent *bindingParent = mContent->GetBindingParent();
nsIContent *parent = bindingParent? bindingParent->GetParent() :
mContent->GetParent();
nsIContent *bindingParent = aElm->GetBindingParent();
nsIContent* parent =
bindingParent? bindingParent->GetParent() : aElm->GetParent();
while (parent) {
if (parent->Tag() == nsGkAtoms::toolbaritem &&
parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
aName.CompressWhitespace();
return eNameOK;
return;
}
parent = parent->GetParent();
}
nsTextEquivUtils::GetNameFromSubtree(this, aName);
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
nsresult
@ -2478,11 +2456,30 @@ Accessible::ARIAName(nsString& aName)
ENameValueFlag
Accessible::NativeName(nsString& aName)
{
if (mContent->IsHTML())
return GetHTMLName(aName);
if (mContent->IsHTML()) {
Accessible* label = nullptr;
HTMLLabelIterator iter(Document(), this);
while ((label = iter.Next())) {
nsTextEquivUtils::AppendTextEquivFromContent(this, label->GetContent(),
&aName);
aName.CompressWhitespace();
}
if (mContent->IsXUL())
return GetXULName(aName);
if (!aName.IsEmpty())
return eNameOK;
nsTextEquivUtils::GetNameFromSubtree(this, aName);
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
if (mContent->IsXUL()) {
XULElmName(mDoc, mContent, aName);
if (!aName.IsEmpty())
return eNameOK;
nsTextEquivUtils::GetNameFromSubtree(this, aName);
return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
}
if (mContent->IsSVG()) {
// If user agents need to choose among multiple desc or title elements

View File

@ -879,10 +879,10 @@ protected:
void ARIAName(nsString& aName);
/**
* Compute the name of HTML/XUL node.
* Return the name for XUL element.
*/
mozilla::a11y::ENameValueFlag GetHTMLName(nsString& aName);
mozilla::a11y::ENameValueFlag GetXULName(nsString& aName);
static void XULElmName(DocAccessible* aDocument,
nsIContent* aElm, nsString& aName);
// helper method to verify frames
static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);

View File

@ -328,16 +328,10 @@ HTMLTextFieldAccessible::NativeName(nsString& aName)
if (!aName.IsEmpty())
return nameFlag;
if (mContent->GetBindingParent()) {
// XXX: bug 459640
// There's a binding parent.
// This means we're part of another control, so use parent accessible for name.
// This ensures that a textbox inside of a XUL widget gets
// an accessible name.
Accessible* parent = Parent();
if (parent)
parent->GetName(aName);
}
// If part of compound of XUL widget then grab a name from XUL widget element.
nsIContent* widgetElm = XULWidgetElm();
if (widgetElm)
XULElmName(mDoc, widgetElm, aName);
if (!aName.IsEmpty())
return eNameOK;
@ -369,8 +363,13 @@ void
HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
{
HyperTextAccessibleWrap::ApplyARIAState(aState);
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
// If part of compound of XUL widget then pick up ARIA stuff from XUL widget
// element.
nsIContent* widgetElm = XULWidgetElm();
if (widgetElm)
aria::MapToState(aria::eARIAAutoComplete, widgetElm->AsElement(), aState);
}
uint64_t
@ -408,9 +407,8 @@ HTMLTextFieldAccessible::NativeState()
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list))
return state | states::SUPPORTS_AUTOCOMPLETION | states::HASPOPUP;
// No parent can mean a fake widget created for XUL textbox. If accessible
// is unattached from tree then we don't care.
if (mParent && Preferences::GetBool("browser.formfill.enable")) {
// Ordinal XUL textboxes don't support autocomplete.
if (!XULWidgetElm() && Preferences::GetBool("browser.formfill.enable")) {
// Check to see if autocompletion is allowed on this input. We don't expose
// it for password fields even though the entire password can be remembered
// for a page if the user asks it to be. However, the kind of autocomplete

View File

@ -143,6 +143,11 @@ public:
protected:
// Accessible
virtual ENameValueFlag NativeName(nsString& aName) MOZ_OVERRIDE;
/**
* Return a XUL widget element this input is part of.
*/
nsIContent* XULWidgetElm() const { return mContent->GetBindingParent(); }
};

View File

@ -636,192 +636,3 @@ XULToolbarSeparatorAccessible::NativeState()
{
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible
////////////////////////////////////////////////////////////////////////////////
XULTextFieldAccessible::
XULTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc) :
HyperTextAccessibleWrap(aContent, aDoc)
{
}
NS_IMPL_ISUPPORTS_INHERITED2(XULTextFieldAccessible,
Accessible,
nsIAccessibleText,
nsIAccessibleEditableText)
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible: nsIAccessible
void
XULTextFieldAccessible::Value(nsString& aValue)
{
aValue.Truncate();
if (NativeRole() == roles::PASSWORD_TEXT) // Don't return password text!
return;
nsCOMPtr<nsIDOMXULTextBoxElement> textBox(do_QueryInterface(mContent));
if (textBox) {
textBox->GetValue(aValue);
return;
}
nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
if (menuList)
menuList->GetLabel(aValue);
}
void
XULTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
{
HyperTextAccessibleWrap::ApplyARIAState(aState);
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
}
uint64_t
XULTextFieldAccessible::NativeState()
{
uint64_t state = HyperTextAccessibleWrap::NativeState();
nsCOMPtr<nsIContent> inputField(GetInputField());
NS_ENSURE_TRUE(inputField, state);
// Create a temporary accessible from the HTML text field to get
// the accessible state from. Doesn't add to cache into document cache.
nsRefPtr<HTMLTextFieldAccessible> tempAccessible =
new HTMLTextFieldAccessible(inputField, mDoc);
if (tempAccessible)
return state | tempAccessible->NativeState();
return state;
}
role
XULTextFieldAccessible::NativeRole()
{
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::password, eIgnoreCase))
return roles::PASSWORD_TEXT;
return roles::ENTRY;
}
/**
* Only one actions available
*/
uint8_t
XULTextFieldAccessible::ActionCount()
{
return 1;
}
/**
* Return the name of our only action
*/
NS_IMETHODIMP
XULTextFieldAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
{
if (aIndex == eAction_Click) {
aName.AssignLiteral("activate");
return NS_OK;
}
return NS_ERROR_INVALID_ARG;
}
/**
* Tell the button to do its action
*/
NS_IMETHODIMP
XULTextFieldAccessible::DoAction(uint8_t index)
{
if (index == 0) {
nsCOMPtr<nsIDOMXULElement> element(do_QueryInterface(mContent));
if (element)
{
element->Focus();
return NS_OK;
}
return NS_ERROR_FAILURE;
}
return NS_ERROR_INVALID_ARG;
}
bool
XULTextFieldAccessible::CanHaveAnonChildren()
{
return false;
}
bool
XULTextFieldAccessible::IsAcceptableChild(Accessible* aPossibleChild) const
{
// XXX: entry shouldn't contain anything but text leafs. Currently it may
// contain a trailing fake HTML br element added for layout needs. We don't
// need to expose it since it'd be confusing for AT.
return aPossibleChild->IsTextLeaf();
}
already_AddRefed<nsIEditor>
XULTextFieldAccessible::GetEditor() const
{
nsCOMPtr<nsIContent> inputField = GetInputField();
nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(inputField));
if (!editableElt)
return nullptr;
nsCOMPtr<nsIEditor> editor;
editableElt->GetEditor(getter_AddRefs(editor));
return editor.forget();
}
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible: Accessible protected
void
XULTextFieldAccessible::CacheChildren()
{
NS_ENSURE_TRUE_VOID(mDoc);
// Create child accessibles for native anonymous content of underlying HTML
// input element.
nsCOMPtr<nsIContent> inputContent(GetInputField());
if (!inputContent)
return;
TreeWalker walker(this, inputContent);
while (Accessible* child = walker.NextChild())
AppendChild(child);
}
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible: HyperTextAccessible protected
already_AddRefed<nsFrameSelection>
XULTextFieldAccessible::FrameSelection() const
{
nsCOMPtr<nsIContent> inputContent(GetInputField());
NS_ASSERTION(inputContent, "No input content");
if (!inputContent)
return nullptr;
nsIFrame* frame = inputContent->GetPrimaryFrame();
return frame ? frame->GetFrameSelection() : nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// XULTextFieldAccessible protected
already_AddRefed<nsIContent>
XULTextFieldAccessible::GetInputField() const
{
nsCOMPtr<nsIDOMNode> inputFieldDOMNode;
nsCOMPtr<nsIDOMXULTextBoxElement> textBox = do_QueryInterface(mContent);
if (textBox)
textBox->GetInputField(getter_AddRefs(inputFieldDOMNode));
NS_ASSERTION(inputFieldDOMNode, "No input field for XULTextFieldAccessible");
nsCOMPtr<nsIContent> inputField = do_QueryInterface(inputFieldDOMNode);
return inputField.forget();
}

View File

@ -215,47 +215,6 @@ public:
virtual uint64_t NativeState();
};
/**
* Used for XUL textbox element.
*/
class XULTextFieldAccessible : public HyperTextAccessibleWrap
{
public:
enum { eAction_Click = 0 };
XULTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc);
NS_DECL_ISUPPORTS_INHERITED
// nsIAccessible
NS_IMETHOD GetActionName(uint8_t aIndex, nsAString& aName);
NS_IMETHOD DoAction(uint8_t index);
// HyperTextAccessible
virtual already_AddRefed<nsIEditor> GetEditor() const;
// Accessible
virtual void Value(nsString& aValue);
virtual void ApplyARIAState(uint64_t* aState) const;
virtual mozilla::a11y::role NativeRole();
virtual uint64_t NativeState();
virtual bool CanHaveAnonChildren();
virtual bool IsAcceptableChild(Accessible* aPossibleChild) const MOZ_OVERRIDE;
// ActionAccessible
virtual uint8_t ActionCount();
protected:
// Accessible
virtual void CacheChildren();
// HyperTextAccessible
virtual already_AddRefed<nsFrameSelection> FrameSelection() const;
// nsXULTextFieldAccessible
already_AddRefed<nsIContent> GetInputField() const;
};
} // namespace a11y
} // namespace mozilla

View File

@ -635,7 +635,7 @@ XULListitemAccessible::NativeName(nsString& aName)
}
}
return GetXULName(aName);
return Accessible::NativeName(aName);
}
role

View File

@ -21,7 +21,6 @@ support-files =
states.js
table.js
value.js
testTextboxes.js
text.js
treeview.css
treeview.js
@ -32,5 +31,3 @@ support-files =
[test_nsIAccessibleDocument.html]
[test_nsIAccessibleImage.html]
[test_OuterDocAccessible.html]
[test_textboxes.html]
[test_textboxes.xul]

View File

@ -91,6 +91,23 @@ function testActions(aArray)
gActionsQueue.invoke();
}
/**
* Test action names and descriptions.
*/
function testActionNames(aID, aActions)
{
var actions = (typeof aActions == "string") ?
[ aActions ] : (aActions || []);
var acc = getAccessible(aID);
is(acc.actionCount, actions.length, "Wong number of actions.");
for (var i = 0; i < actions.length; i++ ) {
is(acc.getActionName(i), actions[i], "Wrong action name at " + i + " index.");
is(acc.getActionDescription(0), gActionDescrMap[actions[i]],
"Wrong action description at " + i + "index.");
}
}
////////////////////////////////////////////////////////////////////////////////
// Private
@ -151,3 +168,20 @@ function checkerOfActionInvoker(aType, aTarget, aActionObj)
aActionObj.checkOnClickEvent(aEvent);
}
}
var gActionDescrMap =
{
jump: "Jump",
press: "Press",
check: "Check",
uncheck: "Uncheck",
select: "Select",
open: "Open",
close: "Close",
switch: "Switch",
click: "Click",
collapse: "Collapse",
expand: "Expand",
activate: "Activate",
cycle: "Cycle"
};

View File

@ -328,6 +328,14 @@ function getApplicationAccessible()
QueryInterface(nsIAccessibleApplication);
}
/**
* A version of accessible tree testing, doesn't fail if tree is not complete.
*/
function testElm(aID, aTreeObj)
{
testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck);
}
/**
* Flags used for testAccessibleTree
*/
@ -370,11 +378,7 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags)
switch (prop) {
case "actions": {
var actions = (typeof accTree.actions == "string") ?
[ accTree.actions ] : (accTree.actions || []);
is(acc.actionCount, actions.length, "Wong number of actions.");
for (var i = 0; i < actions.length; i++ )
is(acc.getActionName(i), actions[i], "Wrong action name at " + i + " index.");
testActionNames(acc, accTree.actions);
break;
}

View File

@ -10,6 +10,8 @@
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../actions.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
@ -22,11 +24,6 @@
src="../name.js"></script>
<script type="application/javascript">
function testElm(aID, aTreeObj)
{
testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck);
}
function doTest()
{
//////////////////////////////////////////////////////////////////////////

View File

@ -28,7 +28,6 @@
function doTests()
{
if (MAC) {
todo(false, "Make these tests pass on OSX (bug 650294)");
SimpleTest.finish();
@ -38,10 +37,11 @@
gQueue = new eventQueue(EVENT_TEXT_CARET_MOVED);
var id = "textbox";
gQueue.push(new synthFocus(id, new caretMoveChecker(5, id)));
gQueue.push(new synthSelectAll(id, new caretMoveChecker(5, id)));
gQueue.push(new synthHomeKey(id, new caretMoveChecker(0, id)));
gQueue.push(new synthRightKey(id, new caretMoveChecker(1, id)));
var input = getNode(id).inputField;
gQueue.push(new synthFocus(id, new caretMoveChecker(5, input)));
gQueue.push(new synthSelectAll(id, new caretMoveChecker(5, input)));
gQueue.push(new synthHomeKey(id, new caretMoveChecker(0, input)));
gQueue.push(new synthRightKey(id, new caretMoveChecker(1, input)));
gQueue.invoke(); // Will call SimpleTest.finish();
}

View File

@ -38,8 +38,10 @@
// Test focus events.
gQueue = new eventQueue();
gQueue.push(new synthFocus("textbox"));
gQueue.push(new synthFocus("textbox_multiline"));
gQueue.push(new synthFocus("textbox",
new focusChecker(getNode("textbox").inputField)));
gQueue.push(new synthFocus("textbox_multiline",
new focusChecker(getNode("textbox_multiline").inputField)));
gQueue.push(new synthFocus("scale"));
gQueue.push(new synthFocusOnFrame("editabledoc"));
gQueue.push(new synthFocus("radioclothes",

View File

@ -22,7 +22,7 @@
<script type="application/javascript">
//gA11yEventDumpID = "eventdump"; // debug stuff
//gA11yEventDumpToConsole = true; // debug stuff
gA11yEventDumpToConsole = true; // debug stuff
var gQueue = null;
function doTests()

View File

@ -36,10 +36,11 @@
// Test focus events.
gQueue = new eventQueue();
var textbox = getNode("textbox").inputField;
gQueue.push(new synthClick("tab1", new focusChecker("tab1")));
gQueue.push(new synthTab("tab1", new focusChecker("checkbox1")));
gQueue.push(new synthKey("tab1", "VK_TAB", { ctrlKey: true },
new focusChecker("textbox")));
new focusChecker(textbox)));
gQueue.push(new synthKey("tab2", "VK_TAB", { ctrlKey: true },
new focusChecker("tab3")));
gQueue.push(new synthKey("tab3", "VK_TAB", { ctrlKey: true },

View File

@ -33,7 +33,7 @@
//////////////////////////////////////////////////////////////////////////
// aria-labelledby
// Single relation. The value of 'aria-labelledby' contains the ID of
// an element. Gets the name from text node of that element.
testName("btn_labelledby_text", "text");

View File

@ -18,11 +18,16 @@
<script type="application/javascript">
<![CDATA[
function getInput(aID)
{
return getNode(aID).inputField;
}
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// Ordinary textbox
testStates("textbox",
testStates(getInput("textbox"),
STATE_FOCUSABLE,
EXT_STATE_EDITABLE,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -31,7 +36,7 @@
//////////////////////////////////////////////////////////////////////////
// Password textbox
testStates("password",
testStates(getInput("password"),
STATE_FOCUSABLE | STATE_PROTECTED,
EXT_STATE_EDITABLE,
STATE_UNAVAILABLE,
@ -40,7 +45,7 @@
//////////////////////////////////////////////////////////////////////////
// Textarea
testStates("textarea",
testStates(getInput("textarea"),
STATE_FOCUSABLE,
EXT_STATE_EDITABLE | EXT_STATE_MULTI_LINE,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -49,7 +54,7 @@
//////////////////////////////////////////////////////////////////////////
// Readonly textbox
testStates("readonly_textbox",
testStates(getInput("readonly_textbox"),
STATE_FOCUSABLE | STATE_READONLY,
EXT_STATE_EDITABLE,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -58,7 +63,7 @@
//////////////////////////////////////////////////////////////////////////
// Disabled textbox
testStates("disabled_textbox",
testStates(getInput("disabled_textbox"),
STATE_UNAVAILABLE,
EXT_STATE_EDITABLE,
STATE_FOCUSABLE | STATE_PROTECTED,
@ -67,7 +72,7 @@
//////////////////////////////////////////////////////////////////////////
// Readonly textarea
testStates("readonly_textarea",
testStates(getInput("readonly_textarea"),
STATE_FOCUSABLE | STATE_READONLY,
EXT_STATE_EDITABLE | EXT_STATE_MULTI_LINE,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -76,7 +81,7 @@
//////////////////////////////////////////////////////////////////////////
// Disabled textarea
testStates("disabled_textarea",
testStates(getInput("disabled_textarea"),
STATE_UNAVAILABLE,
EXT_STATE_EDITABLE| EXT_STATE_MULTI_LINE,
STATE_PROTECTED | STATE_FOCUSABLE,
@ -86,7 +91,7 @@
//////////////////////////////////////////////////////////////////////////
// Search textbox without search button, searches as you type and filters
// a separate control.
testStates("searchbox",
testStates(getInput("searchbox"),
STATE_FOCUSABLE,
EXT_STATE_EDITABLE | EXT_STATE_SUPPORTS_AUTOCOMPLETION,
STATE_PROTECTED | STATE_UNAVAILABLE,
@ -95,7 +100,7 @@
//////////////////////////////////////////////////////////////////////////
// Search textbox with search button, does not support autoCompletion.
testStates("searchfield",
testStates(getInput("searchfield"),
STATE_FOCUSABLE,
EXT_STATE_EDITABLE,
STATE_PROTECTED | STATE_UNAVAILABLE,

View File

@ -1,33 +0,0 @@
function testValue(aID, aAcc, aValue, aRole)
{
is(aAcc.value, aValue, "Wrong value for " + aID + "!");
}
function testAction(aID, aAcc, aActionCount, aActionName, aActionDescription)
{
var actionCount = aAcc.actionCount;
is(actionCount, aActionCount, "Wrong number of actions for " + aID + "!");
if (actionCount != 0) {
// Test first action. Normally only 1 should be present.
is(aAcc.getActionName(0), aActionName,
"Wrong name of action for " + aID + "!");
is(aAcc.getActionDescription(0), aActionDescription,
"Wrong description of action for " + aID + "!");
}
}
function testThis(aID, aName, aValue, aDescription, aRole,
aActionCount, aActionName, aActionDescription)
{
var acc = getAccessible(aID);
if (!acc)
return;
is(acc.name, aName, "Wrong name for " + aID + "!");
testValue(aID, acc, aValue, aRole);
is(acc.description, aDescription, "Wrong description for " + aID + "!");
testRole(aID, aRole);
testAction(aID, acc, aActionCount, aActionName, aActionDescription);
}

View File

@ -1,164 +0,0 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=442648
-->
<head>
<title>nsIAccessible textboxes chrome tests</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="common.js"></script>
<script type="application/javascript"
src="role.js"></script>
<script type="application/javascript"
src="states.js"></script>
<script type="application/javascript"
src="testTextboxes.js"></script>
<script type="application/javascript">
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// normal textbox without content and with no proper label
testThis("unlabelled_Textbox", // ID
null, // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// normal textbox without content and with a proper label
testThis("labelled_textbox", // ID
"Second textbox:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// normal textbox with content and with a proper label
testThis("prefilled_textbox", // ID
"Textbox with predefined value:", // name
"I have some text", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// password textbox with a proper label
testThis("password_textbox", // ID
"Enter some password here:", // name
"", // value
"", // description
ROLE_PASSWORD_TEXT, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea without content and label
testThis("unlabelled_Textarea", // ID
null, // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea without content and with proper label
testThis("labelled_textarea", // ID
"Labelled textarea:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea with content and with proper label
testThis("prefilled_textarea", // ID
"Pre-filled textarea:", // name
" I also have some text.\n ", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// readonly textbox with content and with proper label
testThis("readonly_textbox", // ID
"The following is a read-only textbox:", // name
"You cannot change me.", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// readonly textarea with content and with proper label
testThis("readonly_textarea", // ID
"This textarea is readonly, too:", // name
" You cannot change me, either.\n ", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=442648">Mozilla Bug 442648</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<form action="test.php" method="post">
Text before input without labelling it:
<input type="text" name="unlabelled_Textbox" id="unlabelled_Textbox" size="50"/>
<br><label for="labelled_textbox">Second textbox:</label>
<input type="text" name="labelled_Textbox" id="labelled_textbox"/>
<br><label for="prefilled_textbox">Textbox with predefined value:</label>
<input type="text" name="prefilled_Textbox" id="prefilled_textbox" value="I have some text" size="80"/>
<br><label for="password_textbox">Enter some password here:</label>
<input type="password" name="password_Textbox" id="password_textbox"/>
<br>Textarea without label:<br>
<textarea id="unlabelled_Textarea" name="unlabelled_Textarea" cols="80" rows="5"></textarea>
<br><label for="labelled_textarea">Labelled textarea:</label><br>
<textarea id="labelled_textarea" name="labelled_Textarea" cols="80" rows="5"></textarea>
<br><label for="prefilled_textarea">Pre-filled textarea:</label><br>
<textarea id="prefilled_textarea" name="prefilled_Textarea" cols="80" rows="5">
I also have some text.
</textarea>
<br><label for="readonly_textbox">The following is a read-only textbox:</label>
<input type="text" readonly="true" name="readonly_Textbox" id="readonly_textbox" value="You cannot change me."/>
<br><label for="readonly_textarea">This textarea is readonly, too:</label><br>
<textarea name="readonly_Textarea" id="readonly_textarea" readonly="true" cols="80" rows="5">
You cannot change me, either.
</textarea>
</form>
</body>
</html>

View File

@ -1,217 +0,0 @@
<?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="nsIAccessible XUL textboxes chrome tests">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.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="testTextboxes.js" />
<script type="application/javascript">
<![CDATA[
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// normal textbox without content and with no proper label
testThis("unlabelled_Textbox", // ID
null, // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// normal textbox without content and with a proper label
testThis("labelled_textbox", // ID
"Second textbox:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// normal textbox with content and with a proper label
testThis("prefilled_textbox", // ID
"Textbox with predefined value:", // name
"I have some text", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// password textbox with a proper label
testThis("password_textbox", // ID
"Enter some password here:", // name
"", // value
"", // description
ROLE_PASSWORD_TEXT, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea without content and label
testThis("unlabelled_Textarea", // ID
null, // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea without content and with proper label
testThis("labelled_textarea", // ID
"Labelled textarea:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// textarea with content and with proper label
testThis("prefilled_textarea", // ID
"Pre-filled textarea:", // name
"I also have some text.", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// readonly textbox with content and with proper label
testThis("readonly_textbox", // ID
"The following is a read-only textbox:", // name
"You cannot change me.", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// readonly textarea with content and with proper label
testThis("readonly_textarea", // ID
"This textarea is readonly, too:", // name
"You cannot change me, either.", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// Search textbox without search button, searches as you type and filters
// a separate control.
testThis("search-box", // ID
"Search History:", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
//////////////////////////////////////////////////////////////////////////
// Search textbox with search button, does not support autoCompletion.
testThis("searchfield", // ID
"Search all add-ons", // name
"", // value
"", // description
ROLE_ENTRY, // role
1, // actionCount
"activate", // ActionName
"Activate"); // ActionDescription
testStates("searchfield", 0, 0, 0, EXT_STATE_SUPPORTS_AUTOCOMPLETION);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=442648">
Mozilla Bug 442648
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
<vbox>
<hbox>
<label value="Text before input without labelling it:"/>
<textbox id="unlabelled_Textbox" size="50"/>
</hbox>
<hbox>
<label control="labelled_textbox">Second textbox:</label>
<textbox id="labelled_textbox"/>
</hbox>
<hbox>
<label control="prefilled_textbox">Textbox with predefined value:</label>
<textbox id="prefilled_textbox" value="I have some text" size="80"/>
</hbox>
<hbox>
<label control="password_textbox">Enter some password here:</label>
<textbox type="password" id="password_textbox"/>
</hbox>
<vbox>
<label value="Textarea without label:"/>
<textbox multiline="true" id="unlabelled_Textarea" cols="80" rows="5"/>
</vbox>
<vbox>
<label control="labelled_textarea">Labelled textarea:</label>
<textbox multiline="true" id="labelled_textarea" cols="80" rows="5"/>
</vbox>
<vbox>
<label control="prefilled_textarea">Pre-filled textarea:</label>
<textbox multiline="true" id="prefilled_textarea" cols="80" rows="5"
value="I also have some text."/>
</vbox>
<hbox>
<label control="readonly_textbox">The following is a read-only textbox:</label>
<textbox readonly="true" id="readonly_textbox"
value="You cannot change me."/>
</hbox>
<vbox>
<label control="readonly_textarea">This textarea is readonly, too:</label>
<textbox multiline="true" id="readonly_textarea" readonly="true" cols="80"
rows="5" value="You cannot change me, either."/>
</vbox>
<hbox>
<label value="Search History:" accesskey="S"
control="search-box"/>
<textbox id="search-box" flex="1" type="search"
results="historyTree"/>
</hbox>
<textbox id="searchfield" placeholder="Search all add-ons"
type="search" searchbutton="true"/>
</vbox>
</window>

View File

@ -43,7 +43,7 @@
//////////////////////////////////////////////////////////////////////////
// XUL textbox
testTextAtOffset([ "tbox1" ], BOUNDARY_LINE_START,
testTextAtOffset([ getNode("tbox1").inputField ], BOUNDARY_LINE_START,
[ [ 0, 4, "test", 0, 4 ] ]);
SimpleTest.finish();

View File

@ -23,64 +23,68 @@
function doTest()
{
////////////////////
// textbox
////////////////////
var accTree = {
role: ROLE_ENTRY,
children: [
{
role: ROLE_TEXT_LEAF,
children: []
}
]
};
//////////////////////////////////////////////////////////////////////////
// textboxes
var accTree =
{ SECTION: [
{ ENTRY: [ { TEXT_LEAF: [] } ] },
{ MENUPOPUP: [] }
] };
// default textbox
testAccessibleTree("txc1", accTree);
testAccessibleTree("txc", accTree);
// number textbox
testAccessibleTree("txc2", accTree);
// multiline
testAccessibleTree("txc_multiline", accTree);
//////////////////////////////////////////////////////////////////////////
// search textbox
testAccessibleTree("txc3", accTree);
// timed textbox
testAccessibleTree("txc4_deprecated", accTree);
if (MAC) {
accTree =
{ SECTION: [
{ ENTRY: [ { TEXT_LEAF: [] } ] },
{ MENUPOPUP: [] }
] };
} else {
accTree =
{ SECTION: [
{ ENTRY: [ { TEXT_LEAF: [] } ] },
{ PUSHBUTTON: [] },
{ MENUPOPUP: [] }
] };
}
////////////////////
testAccessibleTree("txc_search", accTree);
//////////////////////////////////////////////////////////////////////////
// number textbox
accTree =
{ SECTION: [
{ ENTRY: [ { TEXT_LEAF: [] } ] },
{ MENUPOPUP: [] },
{ PUSHBUTTON: [] },
{ PUSHBUTTON: [] }
] };
testAccessibleTree("txc_number", accTree);
//////////////////////////////////////////////////////////////////////////
// password textbox
////////////////////
accTree = {
role: ROLE_PASSWORD_TEXT,
children: [
{
role: ROLE_TEXT_LEAF,
children: []
}
]
};
testAccessibleTree("txc5", accTree);
accTree =
{ SECTION: [
{ PASSWORD_TEXT: [ { TEXT_LEAF: [] } ] },
{ MENUPOPUP: [] }
] };
////////////////////
// multiline textbox
////////////////////
accTree = {
role: ROLE_ENTRY,
children: [
{
role: ROLE_TEXT_LEAF,
children: []
}
]
};
testAccessibleTree("txc_password", accTree);
testAccessibleTree("txc6", accTree);
////////////////////
//////////////////////////////////////////////////////////////////////////
// autocomplete textbox
////////////////////
accTree = {
// textbox
role: ROLE_AUTOCOMPLETE,
@ -104,14 +108,14 @@
]
};
function test_txc7() {
testAccessibleTree("txc7", accTree);
function test_AutocompleteControl() {
testAccessibleTree("txc_autocomplete", accTree);
SimpleTest.finish();
}
// XPFE and Toolkit autocomplete widgets differ.
var txc7 = document.getElementById("txc7");
if ("clearResults" in txc7) {
var txc = document.getElementById("txc_autocomplete");
if ("clearResults" in txc) {
SimpleTest.ok(true, "Testing (Old) XPFE autocomplete widget.");
// Popup is always created. (See code below.)
@ -141,14 +145,14 @@
]
}
);
test_txc7();
test_AutocompleteControl();
} else {
SimpleTest.ok(true, "Testing (New) Toolkit autocomplete widget.");
// Dumb access to trigger popup lazy creation.
waitForEvent(EVENT_REORDER, txc7, test_txc7);
txc7.popup;
waitForEvent(EVENT_REORDER, txc, test_AutocompleteControl);
txc.popup;
accTree.children.push(
{
@ -189,15 +193,12 @@
</body>
<vbox flex="1">
<textbox id="txc1" value="hello"/>
<textbox id="txc2" type="number" value="44"/>
<textbox id="txc3" type="search" value="hello"/>
<!-- This textbox triggers "Warning: Timed textboxes are deprecated. Consider using type="search" instead.".
Yet let's test it too as long as it's (still) supported. -->
<textbox id="txc4_deprecated" type="timed" value="hello"/>
<textbox id="txc5" type="password" value="hello"/>
<textbox id="txc6" multiline="true" value="hello"/>
<textbox id="txc7" type="autocomplete" value="hello"/>
<textbox id="txc" value="hello"/>
<textbox id="txc_search" type="search" value="hello"/>
<textbox id="txc_number" type="number" value="44"/>
<textbox id="txc_password" type="password" value="hello"/>
<textbox id="txc_multiline" multiline="true" value="hello"/>
<textbox id="txc_autocomplete" type="autocomplete" value="hello"/>
</vbox>
</hbox>