diff --git a/accessible/public/nsIAccessibleProvider.idl b/accessible/public/nsIAccessibleProvider.idl index eb3137fb86cd..9e2614b5dd65 100644 --- a/accessible/public/nsIAccessibleProvider.idl +++ b/accessible/public/nsIAccessibleProvider.idl @@ -108,48 +108,55 @@ interface nsIAccessibleProvider : nsISupports * Constants set is used by XForms elements. */ - /** Used for xforms elements that provide accessible object for itself as - * well for anonymous content. This property are used for upload, - * input[type="xsd:gDay"] and input[type="xsd:gMonth"] */ - const long XFormsContainer = 0x00002000; + /** Used for xforms elements that provide accessible object for itself as + * well for anonymous content. This property are used for upload, + * input[type="xsd:gDay"] and input[type="xsd:gMonth"] */ + const long XFormsContainer = 0x00002000; - /** Used for label element */ - const long XFormsLabel = 0x00002001; - /** Used for output element */ - const long XFormsOuput = 0x00002002; - /** Used for trigger and submit elements */ - const long XFormsTrigger = 0x00002003; - /** Used for input and textarea elements */ - const long XFormsInput = 0x00002004; - /** Used for input[xsd:boolean] element */ - const long XFormsInputBoolean = 0x00002005; - /** Used for input[xsd:date] element */ - const long XFormsInputDate = 0x00002006; - /** Used for secret element */ - const long XFormsSecret = 0x00002007; - /** Used for range element represented by slider */ - const long XFormsSliderRange = 0x00002008; + /** Used for label element */ + const long XFormsLabel = 0x00002001; + /** Used for output element */ + const long XFormsOuput = 0x00002002; + /** Used for trigger and submit elements */ + const long XFormsTrigger = 0x00002003; + /** Used for input and textarea elements */ + const long XFormsInput = 0x00002004; + /** Used for input[xsd:boolean] element */ + const long XFormsInputBoolean = 0x00002005; + /** Used for input[xsd:date] element */ + const long XFormsInputDate = 0x00002006; + /** Used for secret element */ + const long XFormsSecret = 0x00002007; + /** Used for range element represented by slider */ + const long XFormsSliderRange = 0x00002008; - /** Used for select and select1 that are implemented using host document's - * native widget. For example, a select1 in a xhtml document may be - * represented by the native html control html:select */ - const long XFormsSelect = 0x00002009; - /** Used for xforms choices element */ - const long XFormsChoices = 0x00002010; - /** Used for xforms full select/select1 elements that may be represented by - * group of checkboxes and radiogroup */ - const long XFormsSelectFull = 0x00002011; - /** Used for xforms item element that is used inside xforms select elements - * represented by group of checkboxes */ - const long XFormsItemCheckgroup = 0x00002012; - /** Used for xforms item element that is used inside xforms select1 elements - * represented by radio group */ - const long XFormsItemRadiogroup = 0x00002013; + /** Used for select and select1 that are implemented using host document's + * native widget. For example, a select1 in a xhtml document may be + * represented by the native html control html:select */ + const long XFormsSelect = 0x00002009; + /** Used for xforms choices element */ + const long XFormsChoices = 0x00002010; + /** Used for xforms full select/select1 elements that may be represented by + * group of checkboxes and radiogroup */ + const long XFormsSelectFull = 0x00002011; + /** Used for xforms item element that is used inside xforms select elements + * represented by group of checkboxes */ + const long XFormsItemCheckgroup = 0x00002012; + /** Used for xforms item element that is used inside xforms select1 elements + * represented by radio group */ + const long XFormsItemRadiogroup = 0x00002013; + /** Used for xforms select1 element that is represented by combobox */ + const long XFormsSelectCombobox = 0x00002014; + /** Used for xforms item element that is used inside xforms select1 + * elements represented by combobox */ + const long XFormsItemCombobox = 0x00002015; - /** Used for dropmarker widget that is used by xforms elements */ - const long XFormsDropmarkerWidget = 0x00002101; - /** Used for calendar widget that is used by xforms elements */ - const long XFormsCalendarWidget = 0x00002102; + /** Used for dropmarker widget that is used by xforms elements */ + const long XFormsDropmarkerWidget = 0x00002101; + /** Used for calendar widget that is used by xforms elements */ + const long XFormsCalendarWidget = 0x00002102; + /** Used for popup widget that is used by xforms minimal select1 elements */ + const long XFormsComboboxPopupWidget = 0x00002103; /** * Return one of constants declared above. diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index 8f6a68a0d865..2d58263ea690 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -1587,6 +1587,12 @@ nsresult nsAccessibilityService::GetAccessibleByType(nsIDOMNode *aNode, case nsIAccessibleProvider::XFormsItemRadiogroup: *aAccessible = new nsXFormsItemRadiogroupAccessible(aNode, weakShell); break; + case nsIAccessibleProvider::XFormsSelectCombobox: + *aAccessible = new nsXFormsSelectComboboxAccessible(aNode, weakShell); + break; + case nsIAccessibleProvider::XFormsItemCombobox: + *aAccessible = new nsXFormsItemComboboxAccessible(aNode, weakShell); + break; case nsIAccessibleProvider::XFormsDropmarkerWidget: *aAccessible = new nsXFormsDropmarkerWidgetAccessible(aNode, weakShell); @@ -1594,6 +1600,9 @@ nsresult nsAccessibilityService::GetAccessibleByType(nsIDOMNode *aNode, case nsIAccessibleProvider::XFormsCalendarWidget: *aAccessible = new nsXFormsCalendarWidgetAccessible(aNode, weakShell); break; + case nsIAccessibleProvider::XFormsComboboxPopupWidget: + *aAccessible = new nsXFormsComboboxPopupWidgetAccessible(aNode, weakShell); + break; #endif default: diff --git a/accessible/src/xforms/nsXFormsAccessible.cpp b/accessible/src/xforms/nsXFormsAccessible.cpp index faed67274215..8c88cbd6aa1c 100755 --- a/accessible/src/xforms/nsXFormsAccessible.cpp +++ b/accessible/src/xforms/nsXFormsAccessible.cpp @@ -102,7 +102,7 @@ nsXFormsAccessible::GetBoundChildElementValue(const nsAString& aTagName, } void -nsXFormsAccessible::CacheSelectChildren() +nsXFormsAccessible::CacheSelectChildren(nsIDOMNode *aContainerNode) { if (!mWeakShell) { // This node has been shut down @@ -117,8 +117,13 @@ nsXFormsAccessible::CacheSelectChildren() if (!accService) return; + nsCOMPtr container(aContainerNode); + if (!container) + container = mDOMNode; + nsCOMPtr children; - sXFormsService->GetSelectChildrenFor(mDOMNode, getter_AddRefs(children)); + sXFormsService->GetSelectChildrenFor(container, getter_AddRefs(children)); + if (!children) return; diff --git a/accessible/src/xforms/nsXFormsAccessible.h b/accessible/src/xforms/nsXFormsAccessible.h index 879ed8e9e79d..d07218758aa6 100755 --- a/accessible/src/xforms/nsXFormsAccessible.h +++ b/accessible/src/xforms/nsXFormsAccessible.h @@ -100,7 +100,9 @@ protected: // element. Note, those select/select1 elements that use native widget // for representation don't use the method since their item/choices elements // are hidden and therefore aren't accessible. - void CacheSelectChildren(); + // + // @param aContainerNode - node that contains item elements + void CacheSelectChildren(nsIDOMNode *aContainerNode = nsnull); }; diff --git a/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp b/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp index bb17702ab0a6..18cdc369a7c4 100755 --- a/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp +++ b/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp @@ -562,3 +562,93 @@ nsXFormsItemRadiogroupAccessible::GetActionName(PRUint8 aIndex, nsAString& aName return NS_OK; } + +// nsXFormsSelectComboboxAccessible + +nsXFormsSelectComboboxAccessible:: + nsXFormsSelectComboboxAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell): + nsXFormsSelectableAccessible(aNode, aShell) +{ +} + +NS_IMETHODIMP +nsXFormsSelectComboboxAccessible::GetRole(PRUint32 *aRole) +{ + NS_ENSURE_ARG_POINTER(aRole); + + *aRole = ROLE_COMBOBOX; + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsSelectComboboxAccessible::GetState(PRUint32 *aState) +{ + nsresult rv = nsXFormsSelectableAccessible::GetState(aState); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool isOpen = PR_FALSE; + rv = sXFormsService->IsDropmarkerOpen(mDOMNode, &isOpen); + NS_ENSURE_SUCCESS(rv, rv); + + if (isOpen) + *aState = STATE_EXPANDED; + else + *aState = STATE_COLLAPSED; + + *aState |= STATE_HASPOPUP | STATE_FOCUSABLE; + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsSelectComboboxAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren) +{ + NS_ENSURE_ARG_POINTER(aAllowsAnonChildren); + + *aAllowsAnonChildren = PR_TRUE; + return NS_OK; +} + + +// nsXFormsItemComboboxAccessible + +nsXFormsItemComboboxAccessible:: + nsXFormsItemComboboxAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell): + nsXFormsSelectableItemAccessible(aNode, aShell) +{ +} + +NS_IMETHODIMP +nsXFormsItemComboboxAccessible::GetRole(PRUint32 *aRole) +{ + NS_ENSURE_ARG_POINTER(aRole); + + *aRole = ROLE_LISTITEM; + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsItemComboboxAccessible::GetState(PRUint32 *aState) +{ + nsresult rv = nsXFormsSelectableItemAccessible::GetState(aState); + NS_ENSURE_SUCCESS(rv, rv); + + if (*aState & STATE_UNAVAILABLE) + return NS_OK; + + *aState |= STATE_SELECTABLE; + if (IsItemSelected()) + *aState |= STATE_SELECTED; + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsItemComboboxAccessible::GetActionName(PRUint8 aIndex, nsAString& aName) +{ + if (aIndex != eAction_Click) + return NS_ERROR_INVALID_ARG; + + nsAccessible::GetTranslatedString(NS_LITERAL_STRING("select"), aName); + return NS_OK; +} + diff --git a/accessible/src/xforms/nsXFormsFormControlsAccessible.h b/accessible/src/xforms/nsXFormsFormControlsAccessible.h index ede6cdfce247..be07396f3bfc 100755 --- a/accessible/src/xforms/nsXFormsFormControlsAccessible.h +++ b/accessible/src/xforms/nsXFormsFormControlsAccessible.h @@ -241,5 +241,41 @@ public: NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName); }; + +/** + * Accessible object for xforms:select1 of minimal appearance that is + * represented by combobox. + */ + +class nsXFormsSelectComboboxAccessible : public nsXFormsSelectableAccessible +{ +public: + nsXFormsSelectComboboxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell); + + NS_IMETHOD GetRole(PRUint32 *aRole); + NS_IMETHOD GetState(PRUint32 *aState); + + // Allows accessible nodes in anonymous content of xforms element by + // always returning PR_TRUE value. + NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren); +}; + + +/** + * Accessible object for xforms:item element when it is represented by a + * listitem. This occurs when the item is contained in a xforms:select with + * minimal appearance. Such a xforms:select is represented by a combobox. + */ + +class nsXFormsItemComboboxAccessible : public nsXFormsSelectableItemAccessible +{ +public: + nsXFormsItemComboboxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell); + + NS_IMETHOD GetRole(PRUint32 *aRole); + NS_IMETHOD GetState(PRUint32 *aState); + NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName); +}; + #endif diff --git a/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp b/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp index 0d82f30b6436..7d5bab88004b 100644 --- a/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp +++ b/accessible/src/xforms/nsXFormsWidgetsAccessible.cpp @@ -127,3 +127,73 @@ nsXFormsCalendarWidgetAccessible::GetRole(PRUint32 *aRole) return NS_OK; } + +// nsXFormsComboboxPopupWidgetAccessible + +nsXFormsComboboxPopupWidgetAccessible:: + nsXFormsComboboxPopupWidgetAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell): + nsXFormsAccessible(aNode, aShell) +{ +} + +NS_IMETHODIMP +nsXFormsComboboxPopupWidgetAccessible::GetRole(PRUint32 *aRole) +{ + NS_ENSURE_ARG_POINTER(aRole); + + *aRole = ROLE_LIST; + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsComboboxPopupWidgetAccessible::GetState(PRUint32 *aState) +{ + NS_ENSURE_ARG_POINTER(aState); + + nsXFormsAccessible::GetState(aState); + + PRBool isOpen = PR_FALSE; + nsresult rv = sXFormsService->IsDropmarkerOpen(mDOMNode, &isOpen); + NS_ENSURE_SUCCESS(rv, rv); + + *aState |= STATE_FOCUSABLE; + + if (isOpen) + *aState = STATE_FLOATING; + else + *aState = STATE_INVISIBLE; + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsComboboxPopupWidgetAccessible::GetValue(nsAString& aValue) +{ + aValue.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsComboboxPopupWidgetAccessible::GetName(nsAString& aName) +{ + aName.Truncate(); + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsComboboxPopupWidgetAccessible::GetDescription(nsAString& aDescription) +{ + aDescription.Truncate(); + return NS_OK; +} + +void +nsXFormsComboboxPopupWidgetAccessible::CacheChildren() +{ + nsCOMPtr parent; + mDOMNode->GetParentNode(getter_AddRefs(parent)); + + // Parent node must be an xforms:select1 element. + CacheSelectChildren(parent); +} + diff --git a/accessible/src/xforms/nsXFormsWidgetsAccessible.h b/accessible/src/xforms/nsXFormsWidgetsAccessible.h index 61ca0619b103..2cc360c65961 100644 --- a/accessible/src/xforms/nsXFormsWidgetsAccessible.h +++ b/accessible/src/xforms/nsXFormsWidgetsAccessible.h @@ -74,4 +74,24 @@ public: NS_IMETHOD GetRole(PRUint32 *aRole); }; + +/** + * Accessible object for popup menu of minimal xforms select1 element that is + * represented by combobox. + */ +class nsXFormsComboboxPopupWidgetAccessible : public nsXFormsAccessible +{ +public: + nsXFormsComboboxPopupWidgetAccessible(nsIDOMNode *aNode, + nsIWeakReference *aShell); + + NS_IMETHOD GetRole(PRUint32 *aRole); + NS_IMETHOD GetState(PRUint32 *aState); + NS_IMETHOD GetValue(nsAString& aValue); + NS_IMETHOD GetName(nsAString& aName); + NS_IMETHOD GetDescription(nsAString& aDescription); + + void CacheChildren(); +}; + #endif diff --git a/content/base/public/nsIXFormsUtilityService.h b/content/base/public/nsIXFormsUtilityService.h index 92c2a79c5658..71b16e344d89 100755 --- a/content/base/public/nsIXFormsUtilityService.h +++ b/content/base/public/nsIXFormsUtilityService.h @@ -136,15 +136,16 @@ public: NS_IMETHOD GetEditor(nsIDOMNode *aElement, nsIEditor **aEditor) = 0; /** - * Return true if dropmarker is in open state, otherwise false. Failure if - * given element is not dropmarker or its parent element isn't supposed to - * have dropmarker. + * Return true if dropmarker is in open state (combobox popup is open), + * otherwise false. Failure if given 'aElement' node is not direct child of + * combobox element or is not combobox itself. */ NS_IMETHOD IsDropmarkerOpen(nsIDOMNode *aElement, PRBool* aIsOpen) = 0; /** - * Toggles dropmarker state. Failure if given element is not dropmarker or - * its parent element isn't supposed to have dropmarker. + * Toggles dropmarker state (close/open combobox popup). Failure if given + * 'aElement' node is not direct child of combobox element or is not combobox + * itself. */ NS_IMETHOD ToggleDropmarkerState(nsIDOMNode *aElement) = 0; diff --git a/extensions/xforms/nsXFormsItemElement.cpp b/extensions/xforms/nsXFormsItemElement.cpp index 59e69ca079c5..f658f63632a6 100644 --- a/extensions/xforms/nsXFormsItemElement.cpp +++ b/extensions/xforms/nsXFormsItemElement.cpp @@ -42,6 +42,9 @@ #include "nsXFormsAtoms.h" #include "nsIDOMNodeList.h" #include "nsIDOMDocument.h" +#include "nsIDOMDocumentEvent.h" +#include "nsIDOMEvent.h" +#include "nsIPrivateDOMEvent.h" #include "nsString.h" #include "nsXFormsUtils.h" #include "nsIXFormsValueElement.h" @@ -397,6 +400,33 @@ nsXFormsItemElement::SetActive(PRBool aActive) { /// @see comment in nsIXFormsItemElement.idl + if (aActive) { + // Fire 'DOMMenuItemActive' event. This event is used by accessible module. + nsCOMPtr domDoc; + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); + nsCOMPtr doc = do_QueryInterface(domDoc); + NS_ENSURE_STATE(doc); + + nsCOMPtr event; + doc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event)); + NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); + + event->InitEvent(NS_LITERAL_STRING("DOMMenuItemActive"), + PR_TRUE, PR_TRUE); + + nsCOMPtr node(do_QueryInterface(mElement)); + NS_ENSURE_STATE(node); + + nsXFormsUtils::SetEventTrusted(event, node); + + nsCOMPtr target(do_QueryInterface(mElement)); + NS_ENSURE_STATE(target); + + PRBool defaultActionEnabled = PR_TRUE; + nsresult rv = target->DispatchEvent(event, &defaultActionEnabled); + NS_ENSURE_SUCCESS(rv, rv); + } + NS_NAMED_LITERAL_STRING(active, "_moz_active"); return aActive ? diff --git a/extensions/xforms/nsXFormsUtilityService.cpp b/extensions/xforms/nsXFormsUtilityService.cpp index 99cdcd049652..f663a67fa43b 100644 --- a/extensions/xforms/nsXFormsUtilityService.cpp +++ b/extensions/xforms/nsXFormsUtilityService.cpp @@ -72,9 +72,11 @@ NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);\ #define GET_COMBOBOX_UIWIDGET \ NS_ENSURE_ARG(aElement);\ -nsCOMPtr content(do_QueryInterface(aElement));\ -nsCOMPtr parent(content->GetBindingParent());\ -nsCOMPtr widget(do_QueryInterface(parent));\ +nsCOMPtr widget(do_QueryInterface(aElement));\ +if (!widget) {\ + nsCOMPtr content(do_QueryInterface(aElement));\ + widget = do_QueryInterface(content->GetBindingParent());\ +}\ NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);\ #define GET_XFORMS_SELECT1 \ @@ -367,6 +369,8 @@ nsresult nsXFormsUtilityService::GetSelectChildrenForNodeInternal(nsIDOMNode *aElement, nsNodeList *aNodeList) { + NS_ENSURE_ARG(aElement); + nsCOMPtr children; aElement->GetChildNodes(getter_AddRefs(children)); NS_ENSURE_TRUE(children, NS_ERROR_FAILURE); diff --git a/extensions/xforms/resources/content/select1.xml b/extensions/xforms/resources/content/select1.xml index 5bca6a92e19a..c53b6a57eb5c 100644 --- a/extensions/xforms/resources/content/select1.xml +++ b/extensions/xforms/resources/content/select1.xml @@ -52,13 +52,6 @@ - - - + /> + + + + - + + + + + return Components.interfaces.nsIAccessibleProvider.XFormsSelectCombobox; + + + null null null @@ -201,6 +209,12 @@ if (this._selected) { // Remove extra white space characters from the beginning of the label. this.inputField.value = this._selected.labelText.replace(/^[\s\n]+/, ""); + + // Fire 'ValueChange' event. This event is used by accessible + // module. + var event = this.ownerDocument.createEvent("Events"); + event.initEvent("ValueChange", false, false); + this.dispatchEvent(event); } ]]> @@ -1176,7 +1190,13 @@ - + + + + return Components.interfaces.nsIAccessibleProvider.XFormsItemCombobox; + + + null diff --git a/extensions/xforms/resources/content/widgets-xhtml.xml b/extensions/xforms/resources/content/widgets-xhtml.xml index 9b6f96a1d746..f09e197964b0 100644 --- a/extensions/xforms/resources/content/widgets-xhtml.xml +++ b/extensions/xforms/resources/content/widgets-xhtml.xml @@ -755,5 +755,21 @@ + + + + + + + + + + + return Components.interfaces.nsIAccessibleProvider.XFormsComboboxPopupWidget; + + + + + diff --git a/extensions/xforms/resources/content/xforms.css b/extensions/xforms/resources/content/xforms.css index b742cd0d4d9b..5a7ebb817e7b 100755 --- a/extensions/xforms/resources/content/xforms.css +++ b/extensions/xforms/resources/content/xforms.css @@ -498,6 +498,8 @@ select1 itemset, select itemset { } /* choices widget */ +html|*:root select1:not([appearance]) choices, +html|*:root select1[appearance="minimal] choices, select[appearance='full'] choices, select1[appearance='full'] choices { -moz-binding: url('chrome://xforms/content/selects.xml#choices'); @@ -759,3 +761,7 @@ xul|*:root xul|dropmarker[mozType|dropmarker] { -moz-binding: url('chrome://xforms/content/widgets-xul.xml#dropmarker'); } +html|*:root html|div[mozType|comboboxpopup] { + -moz-binding: url('chrome://xforms/content/widgets-xhtml.xml#comboboxpopup'); +} + diff --git a/extensions/xforms/resources/skin/widgets-xhtml.css b/extensions/xforms/resources/skin/widgets-xhtml.css index 634da66dbcdd..6cc0ee94e692 100644 --- a/extensions/xforms/resources/skin/widgets-xhtml.css +++ b/extensions/xforms/resources/skin/widgets-xhtml.css @@ -135,3 +135,22 @@ input[mozType|dropmarker]:active:hover { border-style: outset; } +/* combobox popup (used inside minimal select1) */ + +div[mozType|comboboxpopup="true"] { + border-width: 1px; + top: 0px; + left: 0px; + border: 1px outset black !important; + background-color: -moz-Field; + font: -moz-list; + text-align: start; + visibility: hidden; + overflow-y: auto; + overflow-x: hidden; + position: absolute; + -moz-user-select: none; + z-index: 2147482647; + cursor: default; +} +