Bug 552944 - No relationship between tabs and associated property page in new tabbrowser construct, r=enn, davidb, marcoz, sr=neil

--HG--
rename : accessible/tests/mochitest/test_relations.html => accessible/tests/mochitest/relations/test_general.html
rename : accessible/tests/mochitest/test_relations.xul => accessible/tests/mochitest/relations/test_general.xul
rename : accessible/tests/mochitest/test_relations_tree.xul => accessible/tests/mochitest/relations/test_tree.xul
This commit is contained in:
Alexander Surkov 2010-05-14 18:55:00 +09:00
parent 0fd15d94da
commit 2548445894
15 changed files with 462 additions and 227 deletions

View File

@ -45,7 +45,7 @@
object. For that XBL binding of element should implement the interface.
*/
[scriptable, uuid(89fb8270-4f25-11df-9879-0800200c9a66)]
[scriptable, uuid(ac0639d5-f95b-4e2b-970c-9eab281fb6a5)]
interface nsIAccessibleProvider : nsISupports
{
/**
@ -92,15 +92,12 @@ interface nsIAccessibleProvider : nsISupports
const long XULRadioButton = 0x00001015;
const long XULRadioGroup = 0x00001016;
/** The single tab in a dialog or tabbrowser/editor interface */
/** Used for XUL tab element */
const long XULTab = 0x00001017;
/** A combination of a tabs object and a tabpanels object */
const long XULTabBox = 0x00001018;
/** The collection of tab objects, usable in the TabBox and independent of it
as well */
const long XULTabs = 0x00001019;
/** Used for XUL tabs element, a container for tab elements */
const long XULTabs = 0x00001018;
/** Used for XUL tabpanels container element */
const long XULTabpanels = 0x00001019;
const long XULText = 0x0000101A;
const long XULTextBox = 0x0000101B;

View File

@ -1916,12 +1916,12 @@ nsAccessibilityService::CreateAccessibleByType(nsIDOMNode *aNode,
case nsIAccessibleProvider::XULTab:
accessible = new nsXULTabAccessible(aNode, aWeakShell);
break;
case nsIAccessibleProvider::XULTabBox:
accessible = new nsXULTabBoxAccessible(aNode, aWeakShell);
break;
case nsIAccessibleProvider::XULTabs:
accessible = new nsXULTabsAccessible(aNode, aWeakShell);
break;
case nsIAccessibleProvider::XULTabpanels:
accessible = new nsXULTabpanelsAccessible(aNode, aWeakShell);
break;
case nsIAccessibleProvider::XULText:
accessible = new nsXULTextAccessible(aNode, aWeakShell);
break;

View File

@ -47,6 +47,7 @@
#include "nsIDOMDocument.h"
#include "nsIDOMXULSelectCntrlEl.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIDOMXULRelatedElement.h"
////////////////////////////////////////////////////////////////////////////////
// nsXULTabAccessible
@ -149,56 +150,20 @@ nsXULTabAccessible::GetRelationByType(PRUint32 aRelationType,
return NS_OK;
// Expose 'LABEL_FOR' relation on tab accessible for tabpanel accessible.
// XXX: It makes sense to require the interface from xul:tab to get linked
// tabpanel element.
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
// Check whether tab and tabpanel are related by 'linkedPanel' attribute on
// xul:tab element.
rv = nsRelUtils::AddTargetFromIDRefAttr(aRelationType, aRelation, content,
nsAccessibilityAtoms::linkedPanel,
PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
if (rv != NS_OK_NO_RELATION_TARGET)
nsCOMPtr<nsIDOMXULRelatedElement> tabsElm =
do_QueryInterface(content->GetParent());
if (!tabsElm)
return NS_OK;
// If there is no 'linkedPanel' attribute on xul:tab element then we
// assume tab and tabpanels are related 1 to 1. We follow algorithm from
// the setter 'selectedIndex' of tabbox.xml#tabs binding.
nsCOMPtr<nsIDOMNode> tabpanelNode;
tabsElm->GetRelatedElement(mDOMNode, getter_AddRefs(tabpanelNode));
if (!tabpanelNode)
return NS_OK;
nsAccessible* tabsAcc = GetParent();
NS_ENSURE_TRUE(nsAccUtils::Role(tabsAcc) == nsIAccessibleRole::ROLE_PAGETABLIST,
NS_ERROR_FAILURE);
PRInt32 tabIndex = -1;
PRInt32 childCount = tabsAcc->GetChildCount();
for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
nsAccessible* childAcc = tabsAcc->GetChildAt(childIdx);
if (nsAccUtils::Role(childAcc) == nsIAccessibleRole::ROLE_PAGETAB)
tabIndex++;
if (childAcc == this)
break;
}
nsAccessible* tabBoxAcc = tabsAcc->GetParent();
NS_ENSURE_TRUE(nsAccUtils::Role(tabBoxAcc) == nsIAccessibleRole::ROLE_PANE,
NS_ERROR_FAILURE);
childCount = tabBoxAcc->GetChildCount();
for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
nsAccessible* childAcc = tabBoxAcc->GetChildAt(childIdx);
if (nsAccUtils::Role(childAcc) == nsIAccessibleRole::ROLE_PROPERTYPAGE) {
if (tabIndex == 0)
return nsRelUtils::AddTarget(aRelationType, aRelation, childAcc);
tabIndex--;
}
}
return NS_OK;
nsCOMPtr<nsIContent> tabpanelContent(do_QueryInterface(tabpanelNode));
return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
tabpanelContent);
}
void
@ -211,40 +176,15 @@ nsXULTabAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
////////////////////////////////////////////////////////////////////////////////
// nsXULTabBoxAccessible
// nsXULTabsAccessible
////////////////////////////////////////////////////////////////////////////////
/**
* XUL TabBox
* to facilitate naming of the tabPanels object we will give this the name
* of the selected tab in the tabs object.
*/
/** Constructor */
nsXULTabBoxAccessible::nsXULTabBoxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
nsAccessibleWrap(aNode, aShell)
{
}
/** We are a window*/
nsresult
nsXULTabBoxAccessible::GetRoleInternal(PRUint32 *aRole)
nsXULTabsAccessible::
nsXULTabsAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell) :
nsXULSelectableAccessible(aNode, aShell)
{
*aRole = nsIAccessibleRole::ROLE_PANE;
return NS_OK;
}
/**
* XUL Tabs - the s really stands for strip. this is a collection of tab objects
*/
/** Constructor */
nsXULTabsAccessible::nsXULTabsAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
nsXULSelectableAccessible(aNode, aShell)
{
}
/** We are a Page Tab List */
nsresult
nsXULTabsAccessible::GetRoleInternal(PRUint32 *aRole)
{
@ -252,10 +192,12 @@ nsXULTabsAccessible::GetRoleInternal(PRUint32 *aRole)
return NS_OK;
}
/** no actions */
NS_IMETHODIMP nsXULTabsAccessible::GetNumActions(PRUint8 *_retval)
NS_IMETHODIMP
nsXULTabsAccessible::GetNumActions(PRUint8 *aCount)
{
*_retval = 0;
NS_ENSURE_ARG_POINTER(aCount);
*aCount = 0;
return NS_OK;
}
@ -272,8 +214,28 @@ nsXULTabsAccessible::GetNameInternal(nsAString& aName)
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsXULTabpanelsAccessible
////////////////////////////////////////////////////////////////////////////////
nsXULTabpanelsAccessible::
nsXULTabpanelsAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell) :
nsAccessibleWrap(aNode, aShell)
{
}
nsresult
nsXULTabpanelsAccessible::GetRoleInternal(PRUint32 *aRole)
{
*aRole = nsIAccessibleRole::ROLE_PANE;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsXULTabpanelAccessible
////////////////////////////////////////////////////////////////////////////////
nsXULTabpanelAccessible::
nsXULTabpanelAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
@ -299,71 +261,18 @@ nsXULTabpanelAccessible::GetRelationByType(PRUint32 aRelationType,
return NS_OK;
// Expose 'LABELLED_BY' relation on tabpanel accessible for tab accessible.
nsCOMPtr<nsIAccessible> tabBoxAcc;
GetParent(getter_AddRefs(tabBoxAcc));
NS_ENSURE_TRUE(nsAccUtils::Role(tabBoxAcc) == nsIAccessibleRole::ROLE_PANE,
NS_ERROR_FAILURE);
PRInt32 tabpanelIndex = -1;
nsCOMPtr<nsIAccessible> tabsAcc;
PRBool isTabpanelFound = PR_FALSE;
nsCOMPtr<nsIAccessible> childAcc;
tabBoxAcc->GetFirstChild(getter_AddRefs(childAcc));
while (childAcc && (!tabsAcc || !isTabpanelFound)) {
if (nsAccUtils::Role(childAcc) == nsIAccessibleRole::ROLE_PAGETABLIST)
tabsAcc = childAcc;
if (!isTabpanelFound &&
nsAccUtils::Role(childAcc) == nsIAccessibleRole::ROLE_PROPERTYPAGE)
tabpanelIndex++;
if (childAcc == this)
isTabpanelFound = PR_TRUE;
nsCOMPtr<nsIAccessible> acc;
childAcc->GetNextSibling(getter_AddRefs(acc));
childAcc.swap(acc);
}
if (!tabsAcc || tabpanelIndex == -1)
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
nsCOMPtr<nsIDOMXULRelatedElement> tabpanelsElm =
do_QueryInterface(content->GetParent());
if (!tabpanelsElm)
return NS_OK;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
nsIAtom *atomID = content->GetID();
nsCOMPtr<nsIDOMNode> tabNode;
tabpanelsElm->GetRelatedElement(mDOMNode, getter_AddRefs(tabNode));
if (!tabNode)
return NS_OK;
nsCOMPtr<nsIAccessible> foundTabAcc;
tabsAcc->GetFirstChild(getter_AddRefs(childAcc));
while (childAcc) {
if (nsAccUtils::Role(childAcc) == nsIAccessibleRole::ROLE_PAGETAB) {
if (atomID) {
nsCOMPtr<nsIAccessNode> tabAccNode(do_QueryInterface(childAcc));
nsCOMPtr<nsIDOMNode> tabNode;
tabAccNode->GetDOMNode(getter_AddRefs(tabNode));
nsCOMPtr<nsIContent> tabContent(do_QueryInterface(tabNode));
NS_ENSURE_TRUE(tabContent, NS_ERROR_FAILURE);
if (tabContent->AttrValueIs(kNameSpaceID_None,
nsAccessibilityAtoms::linkedPanel, atomID,
eCaseMatters)) {
return nsRelUtils::AddTarget(aRelationType, aRelation, childAcc);
}
}
if (tabpanelIndex == 0) {
foundTabAcc = childAcc;
if (!atomID)
break;
}
tabpanelIndex--;
}
nsCOMPtr<nsIAccessible> acc;
childAcc->GetNextSibling(getter_AddRefs(acc));
childAcc.swap(acc);
}
return nsRelUtils::AddTarget(aRelationType, aRelation, foundTabAcc);
nsCOMPtr<nsIContent> tabContent(do_QueryInterface(tabNode));
return nsRelUtils::AddTargetFromContent(aRelationType, aRelation,
tabContent);
}

View File

@ -44,7 +44,7 @@
#include "nsXULMenuAccessible.h"
/**
* An individual tab, xul:tab element
* An individual tab, xul:tab element.
*/
class nsXULTabAccessible : public nsAccessibleWrap
{
@ -67,22 +67,9 @@ public:
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
};
/**
* Contains a tabs object and a tabPanels object. A complete
* entity with relationships between tabs and content to
* be displayed in the tabpanels object
*/
class nsXULTabBoxAccessible : public nsAccessibleWrap
{
public:
nsXULTabBoxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
// nsAccessible
virtual nsresult GetRoleInternal(PRUint32 *aRole);
};
/**
* A container of tab obejcts, xul:tabs element.
* A container of tab objects, xul:tabs element.
*/
class nsXULTabsAccessible : public nsXULSelectableAccessible
{
@ -98,11 +85,29 @@ public:
virtual nsresult GetRoleInternal(PRUint32 *aRole);
};
/**
* A container of tab panels, xul:tabpanels element.
*/
class nsXULTabpanelsAccessible : public nsAccessibleWrap
{
public:
nsXULTabpanelsAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell);
// nsAccessible
virtual nsresult GetRoleInternal(PRUint32 *aRole);
};
/**
* A tabpanel object, child elements of xul:tabpanels element. Note,the object
* is created from nsAccessibilityService::GetAccessibleForDeckChildren()
* method and we do not use nsIAccessibleProvider interface here because
* all children of xul:tabpanels element acts as xul:tabpanel element.
*
* XXX: we need to move the class logic into generic class since
* for example we do not create instance of this class for XUL textbox used as
* a tabpanel.
*/
class nsXULTabpanelAccessible : public nsAccessibleWrap
{

View File

@ -42,7 +42,7 @@ srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = accessible
DIRS = actions attributes events selectable states tree
DIRS = actions attributes events relations selectable states tree
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
@ -104,9 +104,6 @@ _TEST_FILES =\
test_nsIAccessibleImage.html \
test_nsIAccessNode_utils.html \
test_nsOuterDocAccessible.html \
test_relations.html \
test_relations.xul \
test_relations_tree.xul \
test_role_nsHyperTextAcc.html \
test_table_1.html \
test_table_4.html \

View File

@ -0,0 +1,56 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Alexander Surkov <surkov.alexander@gmail.com> (original author)
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = accessible/relations
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
test_general.html \
test_general.xul \
test_tabbrowser.xul \
test_tree.xul \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)

View File

@ -0,0 +1,121 @@
<?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"?>
<?xml-stylesheet href="chrome://browser/content/browser.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Accessible XUL tabbrowser relation tests">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/role.js" />
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/relations.js" />
<script type="application/javascript">
<![CDATA[
////////////////////////////////////////////////////////////////////////////
// Test
const Ci = Components.interfaces;
// Hack to make xul:tabbrowser work.
var handleDroppedLink = null;
Components.utils.import("resource://gre/modules/Services.jsm");
var XULBrowserWindow = {
isBusy: false,
setOverLink: function (link, b) {
}
};
var gFindBar = {
hidden: true
};
function doTest()
{
var tabBrowser = document.getElementById("tabbrowser");
var progressListener =
{
onStateChange: function onStateChange(aWebProgress,
aRequest,
aStateFlags,
aStatus)
{
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP)
testRelations();
}
};
tabBrowser.addProgressListener(progressListener,
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
tabBrowser.loadTabs(["about:", "about:mozilla"], false, true);
}
function testRelations()
{
//////////////////////////////////////////////////////////////////////////
// 'labelled by'/'label for' relations for xul:tab and xul:tabpanel
var tabs = getNode("tabbrowser").tabContainer.childNodes;
var panels = getNode("tabbrowser").mTabBox.tabpanels.childNodes;
testRelation(panels[0], RELATION_LABELLED_BY, tabs[0]);
testRelation(tabs[0], RELATION_LABEL_FOR, panels[0]);
testRelation(panels[1], RELATION_LABELLED_BY, tabs[1]);
testRelation(tabs[1], RELATION_LABEL_FOR, panels[1]);
SimpleTest.finish()
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<vbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=552944"
title="No relationship between tabs and associated property page in new tabbrowser construct">
Mozilla Bug 552944
</a><br/>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<!-- Hack to make xul:tabbrowser work -->
<menubar>
<menu label="menu">
<menupopup>
<menuitem label="close window hook" id="menu_closeWindow"/>
<menuitem label="close hook" id="menu_close"/>
</menupopup>
</menu>
</menubar>
<tabs id="tabbrowser-tabs" class="tabbrowser-tabs"
tabbrowser="tabbrowser"
setfocus="false">
<tab class="tabbrowser-tab" selected="true"/>
</tabs>
<tabbrowser id="tabbrowser"
type="content-primary"
tabcontainer="tabbrowser-tabs"
flex="1"/>
</vbox>
</window>

View File

@ -27,21 +27,23 @@
// tabbox
var accTree = {
role: ROLE_PANE,
role: ROLE_PAGETABLIST,
children: [
{
role: ROLE_PAGETABLIST,
children: [
{
role: ROLE_PAGETAB,
children: []
},
{
role: ROLE_PAGETAB,
children: []
}
]
role: ROLE_PAGETAB,
children: []
},
{
role: ROLE_PAGETAB,
children: []
}
]
};
testAccessibleTree("tabs", accTree);
accTree = {
role: ROLE_PANE,
children: [
{
role: ROLE_PROPERTYPAGE,
children: []
@ -52,7 +54,7 @@
}
]
};
testAccessibleTree("tabbox", accTree);
testAccessibleTree("tabpanels", accTree);
SimpleTest.finish()
}
@ -69,6 +71,11 @@
title=" WARNING: Bad accessible tree!: [tabbrowser tab] ">
Mozilla Bug 540389
</a><br/>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=552944"
title="No relationship between tabs and associated property page in new tabbrowser construct">
Mozilla Bug 552944
</a><br/>
<p id="display"></p>
<div id="content" style="display: none">
</div>
@ -77,12 +84,12 @@
</body>
<vbox flex="1">
<tabbox id="tabbox">
<tabs>
<tabbox>
<tabs id="tabs">
<tab label="tab1"/>
<tab label="tab2"/>
</tabs>
<tabpanels>
<tabpanels id="tabpanels">
<tabpanel/>
<tabpanel/>
</tabpanels>

View File

@ -91,6 +91,8 @@
}
]
};
testAccessibleTree(getNode("tabbrowser").tabContainer, tabsAccTree);
var tabboxAccTree = {
role: ROLE_PANE,
children: [
@ -102,8 +104,9 @@
}
]
};
testAccessibleTree(getNode("tabbrowser").tabContainer, tabsAccTree);
testAccessibleTree(getNode("tabbrowser").mTabBox, tabboxAccTree);
testAccessibleTree(getNode("tabbrowser").mTabBox.tabpanels,
tabboxAccTree);
SimpleTest.finish()
}
@ -120,6 +123,11 @@
title=" WARNING: Bad accessible tree!: [tabbrowser tab] ">
Mozilla Bug 540389
</a><br/>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=552944"
title="No relationship between tabs and associated property page in new tabbrowser construct">
Mozilla Bug 552944
</a><br/>
<p id="display"></p>
<div id="content" style="display: none">
</div>

View File

@ -61,6 +61,7 @@ XPIDLSRCS = \
nsIDOMXULLabeledControlEl.idl \
nsIDOMXULMenuListElement.idl \
nsIDOMXULPopupElement.idl \
nsIDOMXULRelatedElement.idl \
nsIDOMXULSelectCntrlEl.idl \
nsIDOMXULSelectCntrlItemEl.idl \
nsIDOMXULMultSelectCntrlEl.idl \

View File

@ -0,0 +1,51 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
[scriptable, uuid(9fbac05a-fb27-470d-8e5f-028b2dc54ad0)]
interface nsIDOMXULRelatedElement : nsISupports
{
/**
* Retrun an element associated with the given element. It's implemented
* by container elements having relation between their items. For example,
* this interface is implemented by XUL tabs and XUL tabpanels elements
* and used to get XUL tab element by linked tab panel and vice versa.
*/
nsIDOMNode getRelatedElement(in nsIDOMNode aElement);
};

View File

@ -13,15 +13,7 @@
<binding id="tabbox"
extends="chrome://global/content/bindings/tabbox.xml#tab-base">
<implementation implements="nsIDOMEventListener, nsIAccessibleProvider">
<property name="accessibleType" readonly="true">
<getter>
<![CDATA[
return Components.interfaces.nsIAccessibleProvider.XULTabBox;
]]>
</getter>
</property>
<implementation implements="nsIDOMEventListener">
<property name="handleCtrlTab">
<setter>
<![CDATA[
@ -243,7 +235,7 @@
<xul:spacer class="tabs-right" flex="1"/>
</content>
<implementation implements="nsIDOMXULSelectControlElement, nsIAccessibleProvider">
<implementation implements="nsIDOMXULSelectControlElement, nsIDOMXULRelatedElement, nsIAccessibleProvider">
<constructor>
<![CDATA[
// first and last tabs need to be able to have unique styles
@ -278,7 +270,8 @@
this.selectedIndex = 0;
]]>
</constructor>
<!-- nsIAccessibleProvider -->
<property name="accessibleType" readonly="true">
<getter>
<![CDATA[
@ -287,6 +280,55 @@
</getter>
</property>
<!-- nsIDOMXULRelatedElement -->
<method name="getRelatedElement">
<parameter name="aTabElm"/>
<body>
<![CDATA[
if (!aTabElm)
return null;
let tabboxElm = this.tabbox;
if (!tabboxElm)
return null;
let tabpanelsElm = tabboxElm.tabpanels;
if (!tabpanelsElm)
return null;
// Get linked tab panel by 'linkedpanel' attribute on the given tab
// element.
let linkedPanelElm = null;
let linkedPanelId = aTabElm.linkedPanel;
if (linkedPanelId) {
let ownerDoc = this.ownerDocument;
// XXX bug 565858: if XUL tab element is anonymous element then
// suppose linked tab panel is hosted within the same XBL binding
// and search it by ID attribute inside an anonymous content of
// the binding. This is not robust assumption since tab elements may
// live outside a tabbox element so that for example tab elements
// can be explicit content but tab panels can be anonymous.
let bindingParent = ownerDoc.getBindingParent(aTabElm);
if (bindingParent)
return ownerDoc.getAnonymousElementByAttribute(bindingParent,
"id",
linkedPanelId);
return ownerDoc.getElementById(linkedPanelId);
}
// otherwise linked tabpanel element has the same index as the given
// tab element.
let tabElmIdx = this.getIndexOfItem(aTabElm);
return tabpanelsElm.childNodes[tabElmIdx];
]]>
</body>
</method>
<!-- nsIDOMXULSelectControlElement -->
<property name="itemCount" readonly="true"
onget="return this.childNodes.length"/>
@ -347,31 +389,13 @@
this.setAttribute("value", tab.value);
if (this.tabbox) {
let linkedPanel = this.getRelatedElement(tab);
if (linkedPanel) {
this.tabbox.setAttribute("selectedIndex", val);
var tabpanels = this.tabbox.tabpanels;
// This will cause an onselect event to fire for the tabpanel element.
if (tabpanels) {
// find an id
let linkedPanelId = tab.linkedPanel;
let linkedPanel = null;
if (linkedPanelId) {
let ownerDoc = tab.ownerDocument;
let bindingParent = ownerDoc.getBindingParent(tab);
if (bindingParent) {
linkedPanel =
ownerDoc.getAnonymousElementByAttribute(bindingParent,
"id",
linkedPanelId);
}
else
linkedPanel = ownerDoc.getElementById(linkedPanelId);
}
if (linkedPanel)
tabpanels.selectedPanel = linkedPanel;
else
tabpanels.selectedIndex = val;
}
// This will cause an onselect event to fire for the tabpanel
// element.
this.tabbox.tabpanels.selectedPanel = linkedPanel;
}
if (!alreadySelected) {
@ -555,7 +579,66 @@
<binding id="tabpanels"
extends="chrome://global/content/bindings/tabbox.xml#tab-base">
<implementation>
<implementation implements="nsIAccessibleProvider, nsIDOMXULRelatedElement">
<!-- nsIAccessibleProvider -->
<property name="accessibleType" readonly="true">
<getter>
<![CDATA[
return Components.interfaces.nsIAccessibleProvider.XULTabpanels;
]]>
</getter>
</property>
<!-- nsIDOMXULRelatedElement -->
<method name="getRelatedElement">
<parameter name="aTabPanelElm"/>
<body>
<![CDATA[
if (!aTabPanelElm)
return null;
let tabboxElm = this.tabbox;
if (!tabboxElm)
return null;
let tabsElm = tabboxElm.tabs;
if (!tabsElm)
return null;
// Return tab element having 'linkedpanel' attribute equal to the id
// of the tab panel or the same index as the tab panel element.
let tabpanelIdx = Array.indexOf(this.childNodes, aTabPanelElm);
if (tabpanelIdx == -1)
return null;
let tabElms = tabsElm.childNodes;
let tabElmFromIndex = tabElms[tabpanelIdx];
let tabpanelId = aTabPanelElm.id;
if (tabpanelId) {
for (let idx = 0; idx < tabElms.length; idx++) {
var tabElm = tabElms[idx];
if (tabElm.linkedPanel == tabpanelId)
return tabElm;
}
}
return tabElmFromIndex;
]]>
</body>
</method>
<!-- public -->
<field name="tabbox" readonly="true"><![CDATA[
var parent = this.parentNode;
while (parent) {
if (parent.localName == "tabbox")
break;
parent = parent.parentNode;
}
parent;
]]></field>
<field name="_selectedPanel">this.childNodes.item(this.selectedIndex)</field>