зеркало из https://github.com/mozilla/pjs.git
Bug 250006. Clean up GetNextTabbableContent(). Remove tabbable property from DOM interfaces. Clean up spurious focus outline effects. r=bryner, sr=jst
This commit is contained in:
Родитель
1f0c9d8a54
Коммит
0319b80e0e
|
@ -435,6 +435,35 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this content is focusable and in the current tab order.
|
||||
* Note: most callers should use nsIFrame::IsFocusable() instead as it
|
||||
* checks visibility and other layout factors as well.
|
||||
* Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
|
||||
* For example, only the selected radio button in a group is in the
|
||||
* tab order, unless the radio group has no selection in which case
|
||||
* all of the visible, non-disabled radio buttons in the group are
|
||||
* in the tab order. On the other hand, all of the visible, non-disabled
|
||||
* radio buttons are always focusable via clicking or script.
|
||||
* Also, depending on the pref accessibility.tabfocus some widgets may be
|
||||
* focusable but removed from the tab order. This is the default on
|
||||
* Mac OS X, where fewer items are focusable.
|
||||
* @param [inout, optional] aTabIndex the computed tab index
|
||||
* In: default tabindex for element (-1 nonfocusable, == 0 focusable)
|
||||
* Out: computed tabindex
|
||||
* @param [optional] aTabIndex the computed tab index
|
||||
* < 0 if not tabbable
|
||||
* == 0 if in normal tab order
|
||||
* > 0 can be tabbed to in the order specified by this value
|
||||
* @return whether the content is focusable via mouse, kbd or script.
|
||||
*/
|
||||
virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull)
|
||||
{
|
||||
if (aTabIndex)
|
||||
*aTabIndex = -1; // Default, not tabbable
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets content node with the binding responsible for our construction (and
|
||||
* existence). Used by anonymous content (XBL-generated). null for all
|
||||
|
@ -577,6 +606,17 @@ public:
|
|||
PRBool aDumpAll = PR_TRUE) const = 0;
|
||||
#endif
|
||||
|
||||
enum ETabFocusType {
|
||||
//eTabFocus_textControlsMask = (1<<0), // unused - textboxes always tabbable
|
||||
eTabFocus_formElementsMask = (1<<1), // non-text form elements
|
||||
eTabFocus_linksMask = (1<<2), // links
|
||||
eTabFocus_any = 1 + (1<<1) + (1<<2) // everything that can be focused
|
||||
};
|
||||
|
||||
// Tab focus model bit field:
|
||||
static PRInt32 sTabFocusModel;
|
||||
|
||||
|
||||
protected:
|
||||
typedef PRWord PtrBits;
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ DebugListContentTree(nsIContent* aElement)
|
|||
|
||||
PLDHashTable nsGenericElement::sRangeListsHash;
|
||||
PLDHashTable nsGenericElement::sEventListenerManagersHash;
|
||||
|
||||
PRInt32 nsIContent::sTabFocusModel = eTabFocus_any;
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsChildContentList::nsChildContentList(nsIContent *aContent)
|
||||
|
|
|
@ -108,7 +108,6 @@ public:
|
|||
// If aCanFocusDoc == PR_TRUE, the current document will be focused if caret is not on a focusable element
|
||||
NS_IMETHOD MoveFocusToCaret(PRBool aCanFocusDoc, PRBool *aIsSelectionWithFocus) = 0;
|
||||
NS_IMETHOD MoveCaretToFocus() = 0;
|
||||
NS_IMETHOD GetTabbable(PRInt32 aTabFocusType, PRBool *aIsTabbable) = 0;
|
||||
|
||||
// This is an experiment and may be temporary
|
||||
NS_IMETHOD ConsumeFocusEvents(PRBool aDoConsume) = 0;
|
||||
|
@ -144,12 +143,4 @@ enum EFocusedWithType {
|
|||
eEventFocusedByApplication // focus gained via Application (like script)
|
||||
};
|
||||
|
||||
// Tab focus model bit field:
|
||||
enum ETabFocusType {
|
||||
//eTabFocus_textControlsMask = (1<<0), // unused - textboxes always tabbable
|
||||
eTabFocus_formElementsMask = (1<<1), // non-text form elements
|
||||
eTabFocus_linksMask = (1<<2), // links
|
||||
eTabFocus_any = 1 + (1<<1) + (1<<2) // everything that can be focused
|
||||
};
|
||||
|
||||
#endif // nsIEventStateManager_h__
|
||||
|
|
|
@ -155,7 +155,6 @@ static PRBool sLeftClickOnly = PR_TRUE;
|
|||
static PRBool sKeyCausesActivation = PR_TRUE;
|
||||
static PRUint32 sESMInstanceCount = 0;
|
||||
static PRInt32 sGeneralAccesskeyModifier = -1; // magic value of -1 means uninitialized
|
||||
static PRInt32 sTabFocusModel = eTabFocus_any;
|
||||
|
||||
enum {
|
||||
MOUSE_SCROLL_N_LINES,
|
||||
|
@ -260,8 +259,9 @@ nsEventStateManager::Init()
|
|||
nsContentUtils::GetIntPref("ui.key.generalAccessKey",
|
||||
sGeneralAccesskeyModifier);
|
||||
|
||||
sTabFocusModel = nsContentUtils::GetIntPref("accessibility.tabfocus",
|
||||
sTabFocusModel);
|
||||
nsIContent::sTabFocusModel =
|
||||
nsContentUtils::GetIntPref("accessibility.tabfocus",
|
||||
nsIContent::sTabFocusModel);
|
||||
}
|
||||
prefBranch->AddObserver("accessibility.accesskeycausesactivation", this, PR_TRUE);
|
||||
prefBranch->AddObserver("accessibility.browsewithcaret", this, PR_TRUE);
|
||||
|
@ -382,8 +382,9 @@ nsEventStateManager::Observe(nsISupports *aSubject,
|
|||
} else if (data.EqualsLiteral("accessibility.browsewithcaret")) {
|
||||
ResetBrowseWithCaret();
|
||||
} else if (data.EqualsLiteral("accessibility.tabfocus")) {
|
||||
sTabFocusModel = nsContentUtils::GetIntPref("accessibility.tabfocus",
|
||||
sTabFocusModel);
|
||||
nsIContent::sTabFocusModel =
|
||||
nsContentUtils::GetIntPref("accessibility.tabfocus",
|
||||
nsIContent::sTabFocusModel);
|
||||
} else if (data.EqualsLiteral("nglayout.events.dispatchLeftClickOnly")) {
|
||||
sLeftClickOnly =
|
||||
nsContentUtils::GetBoolPref("nglayout.events.dispatchLeftClickOnly",
|
||||
|
@ -1916,9 +1917,7 @@ nsEventStateManager::PostHandleEvent(nsIPresContext* aPresContext,
|
|||
break;
|
||||
}
|
||||
|
||||
const nsStyleUserInterface* ui = currFrame->GetStyleUserInterface();
|
||||
if ((ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE) &&
|
||||
(ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE)) {
|
||||
if (currFrame->IsFocusable()) {
|
||||
newFocus = currFrame->GetContent();
|
||||
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocus));
|
||||
if (domElement)
|
||||
|
@ -3393,35 +3392,6 @@ nsEventStateManager::TabIndexFrom(nsIContent *aFrom, PRInt32 *aOutIndex)
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsEventStateManager::HasFocusableAncestor(nsIFrame *aFrame)
|
||||
{
|
||||
// This method helps prevent a situation where a link or other element
|
||||
// with -moz-user-focus is focused twice, because the parent link
|
||||
// would get focused, and all of the children also get focus.
|
||||
|
||||
nsIFrame *ancestorFrame = aFrame;
|
||||
while ((ancestorFrame = ancestorFrame->GetParent()) != nsnull) {
|
||||
nsIContent *ancestorContent = ancestorFrame->GetContent();
|
||||
if (!ancestorContent) {
|
||||
break;
|
||||
}
|
||||
nsIAtom *ancestorTag = ancestorContent->Tag();
|
||||
if (ancestorTag == nsHTMLAtoms::frame || ancestorTag == nsHTMLAtoms::iframe) {
|
||||
break; // The only focusable containers that can also have focusable children
|
||||
}
|
||||
// Any other parent that's focusable can't have focusable children
|
||||
const nsStyleUserInterface *ui = ancestorFrame->GetStyleUserInterface();
|
||||
if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
|
||||
ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
|
||||
// Inside a focusable parent -- let parent get focus
|
||||
// instead of child (to avoid links within links etc.)
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEventStateManager::GetNextTabbableContent(nsIContent* aRootContent,
|
||||
nsIContent* aStartContent,
|
||||
|
@ -3433,286 +3403,128 @@ nsEventStateManager::GetNextTabbableContent(nsIContent* aRootContent,
|
|||
{
|
||||
*aResultNode = nsnull;
|
||||
*aResultFrame = nsnull;
|
||||
PRBool keepFirstFrame = PR_FALSE;
|
||||
PRBool findLastFrame = PR_FALSE;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIFrameTraversal> trav(do_CreateInstance(kFrameTraversalCID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIBidirectionalEnumerator> frameTraversal;
|
||||
|
||||
// --- Get frame to start with ---
|
||||
if (!aStartFrame) {
|
||||
//No frame means we need to start with the root content again.
|
||||
if (mPresContext) {
|
||||
nsIFrame* result = nsnull;
|
||||
nsIPresShell *presShell = mPresContext->GetPresShell();
|
||||
if (presShell) {
|
||||
presShell->GetPrimaryFrameFor(aRootContent, &result);
|
||||
}
|
||||
|
||||
aStartFrame = result;
|
||||
|
||||
if (!forward)
|
||||
findLastFrame = PR_TRUE;
|
||||
// No frame means we need to start with the root content again.
|
||||
NS_ENSURE_TRUE(mPresContext, NS_ERROR_FAILURE);
|
||||
nsIPresShell *presShell = mPresContext->GetPresShell();
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
presShell->GetPrimaryFrameFor(aRootContent, &aStartFrame);
|
||||
NS_ENSURE_TRUE(aStartFrame, NS_ERROR_FAILURE);
|
||||
rv = trav->NewFrameTraversal(getter_AddRefs(frameTraversal), FOCUS,
|
||||
mPresContext, aStartFrame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!forward) {
|
||||
rv = frameTraversal->Last();
|
||||
}
|
||||
if (!aStartFrame) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
keepFirstFrame = PR_TRUE;
|
||||
}
|
||||
|
||||
// Need to do special check in case we're in an imagemap which has multiple content per frame
|
||||
if (aStartContent) {
|
||||
if (aStartContent->Tag() == nsHTMLAtoms::area &&
|
||||
aStartContent->IsContentOfType(nsIContent::eHTML)) {
|
||||
// We're starting from an imagemap area, so don't skip over the starting frame.
|
||||
keepFirstFrame = PR_TRUE;
|
||||
else {
|
||||
rv = trav->NewFrameTraversal(getter_AddRefs(frameTraversal), FOCUS,
|
||||
mPresContext, aStartFrame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!aStartContent || aStartContent->Tag() != nsHTMLAtoms::area ||
|
||||
!aStartContent->IsContentOfType(nsIContent::eHTML)) {
|
||||
// Need to do special check in case we're in an imagemap which has multiple
|
||||
// content per frame, so don't skip over the starting frame.
|
||||
rv = forward ? frameTraversal->Next() : frameTraversal->Prev();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult result;
|
||||
nsCOMPtr<nsIFrameTraversal> trav(do_CreateInstance(kFrameTraversalCID,&result));
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
|
||||
result = trav->NewFrameTraversal(getter_AddRefs(frameTraversal), FOCUS,
|
||||
mPresContext, aStartFrame);
|
||||
if (NS_FAILED(result))
|
||||
return NS_OK;
|
||||
|
||||
if (!keepFirstFrame) {
|
||||
if (forward)
|
||||
frameTraversal->Next();
|
||||
else frameTraversal->Prev();
|
||||
} else if (findLastFrame)
|
||||
frameTraversal->Last();
|
||||
|
||||
nsISupports* currentItem;
|
||||
frameTraversal->CurrentItem(¤tItem);
|
||||
nsIFrame* currentFrame = (nsIFrame*)currentItem;
|
||||
|
||||
while (currentFrame) {
|
||||
const nsStyleVisibility* vis = currentFrame->GetStyleVisibility();
|
||||
const nsStyleUserInterface* ui = currentFrame->GetStyleUserInterface();
|
||||
|
||||
PRBool viewShown = currentFrame->AreAncestorViewsVisible();
|
||||
|
||||
nsIContent* child = currentFrame->GetContent();
|
||||
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(child));
|
||||
PRInt32 tabIndex = -1;
|
||||
|
||||
if (element && viewShown) {
|
||||
if (vis->mVisible != NS_STYLE_VISIBILITY_COLLAPSE &&
|
||||
vis->mVisible != NS_STYLE_VISIBILITY_HIDDEN &&
|
||||
ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
|
||||
ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
|
||||
tabIndex = 0; // Default value when focusable via -moz-user-focus
|
||||
}
|
||||
TabIndexFrom(child, &tabIndex);
|
||||
// -- Walk frames to find something tabbable matching mCurrentTabIndex --
|
||||
while (NS_SUCCEEDED(rv)) {
|
||||
nsISupports* currentItem;
|
||||
frameTraversal->CurrentItem(¤tItem);
|
||||
*aResultFrame = (nsIFrame*)currentItem;
|
||||
if (!*aResultFrame) {
|
||||
break;
|
||||
}
|
||||
// if collapsed or hidden, we don't get tabbed into.
|
||||
|
||||
// TabIndex not set defaults to 0 for form elements, anchors and other
|
||||
// elements that are normally focusable. Tabindex defaults to -1
|
||||
// for elements that are not normally focusable.
|
||||
// The returned computed tabindex from IsFocusable() is as follows:
|
||||
// < 0 not tabbable at all
|
||||
// == 0 in normal tab order (last after positive tabindex'd items)
|
||||
// > 0 can be tabbed to in the order specified by this value
|
||||
PRInt32 tabIndex;
|
||||
nsIContent* currentContent = (*aResultFrame)->GetContent();
|
||||
(*aResultFrame)->IsFocusable(&tabIndex);
|
||||
if (tabIndex >= 0) {
|
||||
PRBool disabled = PR_TRUE;
|
||||
|
||||
nsIAtom *tag = child->Tag();
|
||||
if (child->IsContentOfType(nsIContent::eHTML)) {
|
||||
if (tag == nsHTMLAtoms::input) {
|
||||
nsCOMPtr<nsIDOMNSHTMLInputElement> nextInputNS(do_QueryInterface(child));
|
||||
NS_ASSERTION(nextInputNS, "input element must QI to nsIDOMNSHTMLInputElement!");
|
||||
PRBool isTabbable;
|
||||
nextInputNS->GetTabbable(&isTabbable);
|
||||
disabled = !isTabbable;
|
||||
}
|
||||
else if (tag == nsHTMLAtoms::select) {
|
||||
// Select counts as form but not as text
|
||||
disabled = !(sTabFocusModel & eTabFocus_formElementsMask);
|
||||
if (!disabled) {
|
||||
nsCOMPtr<nsIDOMHTMLSelectElement> nextSelect(do_QueryInterface(child));
|
||||
if (nextSelect) {
|
||||
nextSelect->GetDisabled(&disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tag == nsHTMLAtoms::textarea) {
|
||||
// it's a textarea
|
||||
disabled = PR_FALSE;
|
||||
if (!disabled) {
|
||||
nsCOMPtr<nsIDOMHTMLTextAreaElement> nextTextArea(do_QueryInterface(child));
|
||||
if (nextTextArea) {
|
||||
nextTextArea->GetDisabled(&disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tag == nsHTMLAtoms::a) {
|
||||
// it's a link
|
||||
disabled = !(sTabFocusModel & eTabFocus_linksMask);
|
||||
nsCOMPtr<nsIDOMHTMLAnchorElement> nextAnchor(do_QueryInterface(child));
|
||||
if (!disabled) {
|
||||
nsAutoString href;
|
||||
nextAnchor->GetAttribute(NS_LITERAL_STRING("href"), href);
|
||||
if (href.IsEmpty()) {
|
||||
disabled = PR_TRUE; // Don't tab unless href, bug 17605
|
||||
} else {
|
||||
disabled = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tag == nsHTMLAtoms::button) {
|
||||
// Button counts as a form element but not as text
|
||||
disabled = !(sTabFocusModel & eTabFocus_formElementsMask);
|
||||
if (!disabled) {
|
||||
nsCOMPtr<nsIDOMHTMLButtonElement> nextButton(do_QueryInterface(child));
|
||||
if (nextButton) {
|
||||
nextButton->GetDisabled(&disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tag == nsHTMLAtoms::img) {
|
||||
PRBool hasImageMap = PR_FALSE;
|
||||
// Don't need to set disabled here, because if we
|
||||
// match an imagemap, we'll return from there.
|
||||
nsCOMPtr<nsIDOMHTMLImageElement> nextImage(do_QueryInterface(child));
|
||||
nsAutoString usemap;
|
||||
if (nextImage) {
|
||||
nsCOMPtr<nsIDocument> doc = child->GetDocument();
|
||||
if (doc) {
|
||||
nextImage->GetAttribute(NS_LITERAL_STRING("usemap"), usemap);
|
||||
nsCOMPtr<nsIDOMHTMLMapElement> imageMap = nsImageMapUtils::FindImageMap(doc,usemap);
|
||||
if (imageMap) {
|
||||
hasImageMap = PR_TRUE;
|
||||
if (sTabFocusModel & eTabFocus_linksMask) {
|
||||
nsCOMPtr<nsIContent> map(do_QueryInterface(imageMap));
|
||||
if (map) {
|
||||
nsIContent *childArea;
|
||||
PRUint32 index, count = map->GetChildCount();
|
||||
// First see if mCurrentFocus is in this map
|
||||
for (index = 0; index < count; index++) {
|
||||
childArea = map->GetChildAt(index);
|
||||
if (childArea == mCurrentFocus) {
|
||||
PRInt32 val = 0;
|
||||
TabIndexFrom(childArea, &val);
|
||||
if (mCurrentTabIndex == val) {
|
||||
// mCurrentFocus is in this map so we must start
|
||||
// iterating past it.
|
||||
// We skip the case where mCurrentFocus has the
|
||||
// same tab index as mCurrentTabIndex since the
|
||||
// next tab ordered element might be before it
|
||||
// (or after for backwards) in the child list.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
PRInt32 increment = forward ? 1 : -1;
|
||||
// In the following two lines we might substract 1 from zero,
|
||||
// the |index < count| loop condition will be false in that case too.
|
||||
index = index < count ? index + increment : (forward ? 0 : count - 1);
|
||||
for (; index < count; index += increment) {
|
||||
//Iterate over the children.
|
||||
childArea = map->GetChildAt(index);
|
||||
|
||||
//Got the map area, check its tabindex.
|
||||
PRInt32 val = 0;
|
||||
TabIndexFrom(childArea, &val);
|
||||
if (mCurrentTabIndex == val) {
|
||||
//tabindex == the current one, use it.
|
||||
*aResultNode = childArea;
|
||||
NS_IF_ADDREF(*aResultNode);
|
||||
*aResultFrame = currentFrame;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Might be using -moz-user-focus and imitating a control.
|
||||
// If already inside link, -moz-user-focus'd element, or already has
|
||||
// image map with tab stops, then don't use the
|
||||
// image frame itself as a tab stop.
|
||||
disabled = HasFocusableAncestor(currentFrame) || hasImageMap ||
|
||||
!(sTabFocusModel & eTabFocus_formElementsMask);
|
||||
}
|
||||
else if (tag == nsHTMLAtoms::object) {
|
||||
// OBJECT is treated as a form element.
|
||||
disabled = !(sTabFocusModel & eTabFocus_formElementsMask);
|
||||
}
|
||||
else if (tag == nsHTMLAtoms::iframe || tag == nsHTMLAtoms::frame) {
|
||||
disabled = PR_TRUE;
|
||||
if (child) {
|
||||
nsCOMPtr<nsIDocument> doc = child->GetDocument();
|
||||
if (doc) {
|
||||
nsIDocument *subDoc = doc->GetSubDocumentFor(child);
|
||||
if (subDoc) {
|
||||
nsCOMPtr<nsISupports> container = subDoc->GetContainer();
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsIContentViewer> contentViewer;
|
||||
docShell->GetContentViewer(getter_AddRefs(contentViewer));
|
||||
if (contentViewer) {
|
||||
nsCOMPtr<nsIContentViewer> zombieViewer;
|
||||
contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
|
||||
if (!zombieViewer) {
|
||||
// If there are 2 viewers for the current docshell, that
|
||||
// means the current document is a zombie document.
|
||||
// Only navigate into the frame/iframe if it's not a zombie
|
||||
disabled = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Let any HTML element with -moz-user-focus: normal be tabbable
|
||||
// Without this rule, DHTML form controls made from div or span
|
||||
// cannot be put in the tab order.
|
||||
disabled = !(sTabFocusModel & eTabFocus_formElementsMask) ||
|
||||
HasFocusableAncestor(currentFrame);
|
||||
if (currentContent->Tag() == nsHTMLAtoms::img &&
|
||||
currentContent->HasAttr(kNameSpaceID_None, nsHTMLAtoms::usemap)) {
|
||||
// Must be an image w/ a map -- it's tabbable but no tabindex is specified
|
||||
// Special case for image maps: they don't get walked by nsIFrameTraversal
|
||||
nsIContent *areaContent = GetNextTabbableMapArea(forward, currentContent);
|
||||
if (areaContent) {
|
||||
NS_ADDREF(*aResultNode = areaContent);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Is it disabled?
|
||||
nsAutoString value;
|
||||
child->GetAttr(kNameSpaceID_None, nsHTMLAtoms::disabled, value);
|
||||
if (!value.EqualsLiteral("true")) {
|
||||
nsCOMPtr<nsIDOMXULControlElement> control(do_QueryInterface(child));
|
||||
if (control)
|
||||
control->GetDisabled(&disabled);
|
||||
else
|
||||
disabled = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// TabIndex not set treated at same level as set to 0
|
||||
if (!disabled && (aIgnoreTabIndex || mCurrentTabIndex == tabIndex) &&
|
||||
child != aStartContent) {
|
||||
*aResultNode = child;
|
||||
NS_IF_ADDREF(*aResultNode);
|
||||
*aResultFrame = currentFrame;
|
||||
else if ((aIgnoreTabIndex || mCurrentTabIndex == tabIndex) &&
|
||||
currentContent != aStartContent) {
|
||||
NS_ADDREF(*aResultNode = currentContent);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (forward)
|
||||
frameTraversal->Next();
|
||||
else frameTraversal->Prev();
|
||||
|
||||
frameTraversal->CurrentItem(¤tItem);
|
||||
currentFrame = (nsIFrame*)currentItem;
|
||||
rv = forward ? frameTraversal->Next() : frameTraversal->Prev();
|
||||
}
|
||||
|
||||
// Reached end or beginning of document
|
||||
//If already at lowest priority tab (0), end
|
||||
if (((forward) && (0 == mCurrentTabIndex)) ||
|
||||
((!forward) && (1 == mCurrentTabIndex))) {
|
||||
// -- Reached end or beginning of document --
|
||||
|
||||
// If already at lowest priority tab (0), end search completely.
|
||||
// A bit counterintuitive but true, tabindex order goes 1, 2, ... 32767, 0
|
||||
if (mCurrentTabIndex == (forward? 0: 1)) {
|
||||
return NS_OK;
|
||||
}
|
||||
//else continue looking for next highest priority tab
|
||||
|
||||
// else continue looking for next highest priority tabindex
|
||||
mCurrentTabIndex = GetNextTabIndex(aRootContent, forward);
|
||||
return GetNextTabbableContent(aRootContent, aStartContent, nsnull, forward,
|
||||
aIgnoreTabIndex, aResultNode, aResultFrame);
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsEventStateManager::GetNextTabbableMapArea(PRBool aForward,
|
||||
nsIContent *aImageContent)
|
||||
{
|
||||
nsAutoString useMap;
|
||||
aImageContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::usemap, useMap);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = aImageContent->GetDocument();
|
||||
if (doc) {
|
||||
nsCOMPtr<nsIDOMHTMLMapElement> imageMap = nsImageMapUtils::FindImageMap(doc, useMap);
|
||||
nsCOMPtr<nsIContent> mapContent = do_QueryInterface(imageMap);
|
||||
PRUint32 count = mapContent->GetChildCount();
|
||||
// First see if mCurrentFocus is in this map
|
||||
PRInt32 index = mapContent->IndexOf(mCurrentFocus);
|
||||
PRInt32 tabIndex;
|
||||
if (index < 0 || (mCurrentFocus->IsFocusable(&tabIndex) &&
|
||||
tabIndex != mCurrentTabIndex)) {
|
||||
// If mCurrentFocus is in this map we must start iterating past it.
|
||||
// We skip the case where mCurrentFocus has tabindex == mCurrentTabIndex
|
||||
// since the next tab ordered element might be before it
|
||||
// (or after for backwards) in the child list.
|
||||
index = aForward? -1 : count;
|
||||
}
|
||||
|
||||
// GetChildAt will return nsnull if our index < 0 or index >= count
|
||||
nsCOMPtr<nsIContent> areaContent;
|
||||
while ((areaContent = mapContent->GetChildAt(aForward? ++index : --index)) != nsnull) {
|
||||
if (areaContent->IsFocusable(&tabIndex) && tabIndex == mCurrentTabIndex) {
|
||||
return areaContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsEventStateManager::GetNextTabIndex(nsIContent* aParent, PRBool forward)
|
||||
{
|
||||
|
@ -5134,12 +4946,6 @@ nsEventStateManager::ResetBrowseWithCaret()
|
|||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsEventStateManager::GetTabbable(PRInt32 aTabFocusType, PRBool *aIsTabbable)
|
||||
{
|
||||
*aIsTabbable = (sTabFocusModel & aTabFocusType) != 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
//-- DocShell Focus Traversal Methods
|
||||
//--------------------------------------------------------------------------------
|
||||
|
|
|
@ -145,7 +145,6 @@ public:
|
|||
|
||||
NS_IMETHOD MoveFocusToCaret(PRBool aCanFocusDoc, PRBool *aIsSelectionWithFocus);
|
||||
NS_IMETHOD MoveCaretToFocus();
|
||||
NS_IMETHOD GetTabbable(PRInt32 aTabFocusType, PRBool *aIsTabbable);
|
||||
|
||||
protected:
|
||||
friend class CurrentEventShepherd;
|
||||
|
@ -167,13 +166,13 @@ protected:
|
|||
nsresult SetClickCount(nsIPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus);
|
||||
nsresult CheckForAndDispatchClick(nsIPresContext* aPresContext, nsMouseEvent *aEvent, nsEventStatus* aStatus);
|
||||
PRBool ChangeFocus(nsIContent* aFocus, PRInt32 aFocusedWith);
|
||||
static PRBool HasFocusableAncestor(nsIFrame *aFrame);
|
||||
nsresult GetNextTabbableContent(nsIContent* aRootContent,
|
||||
nsIContent* aStartContent,
|
||||
nsIFrame* aStartFrame,
|
||||
PRBool forward, PRBool ignoreTabIndex,
|
||||
nsIContent** aResultNode,
|
||||
nsIFrame** aResultFrame);
|
||||
nsIContent *GetNextTabbableMapArea(PRBool aForward, nsIContent *imageContent);
|
||||
|
||||
void TabIndexFrom(nsIContent *aFrom, PRInt32 *aOutIndex);
|
||||
PRInt32 GetNextTabIndex(nsIContent* aParent, PRBool foward);
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsINodeInfo.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsICSSParser.h"
|
||||
#include "nsICSSLoader.h"
|
||||
#include "nsICSSStyleRule.h"
|
||||
|
@ -1374,14 +1375,11 @@ nsGenericHTMLElement::HandleDOMEvent(nsIPresContext* aPresContext,
|
|||
!(aFlags & (NS_EVENT_FLAG_CAPTURE | NS_EVENT_FLAG_SYSTEM_EVENT)) &&
|
||||
aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN &&
|
||||
!IsContentOfType(eHTML_FORM_CONTROL) &&
|
||||
HasAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex)) {
|
||||
HasAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex) &&
|
||||
IsFocusable()) {
|
||||
// Any visible element is focusable if tabindex >= 0
|
||||
PRInt32 tabIndex;
|
||||
GetTabIndex(&tabIndex);
|
||||
if (tabIndex >= 0) {
|
||||
Focus();
|
||||
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
ret = Focus();
|
||||
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -3300,6 +3298,45 @@ nsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsGenericHTMLFrameElement::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
if (!nsGenericHTMLElement::IsFocusable(aTabIndex)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// If there is no subdocument, docshell or content viewer, it's not tabbable
|
||||
PRBool isFocusable = PR_FALSE;
|
||||
if (mDocument) {
|
||||
nsIDocument *subDoc = mDocument->GetSubDocumentFor(this);
|
||||
if (subDoc) {
|
||||
nsCOMPtr<nsISupports> container = subDoc->GetContainer();
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsIContentViewer> contentViewer;
|
||||
docShell->GetContentViewer(getter_AddRefs(contentViewer));
|
||||
if (contentViewer) {
|
||||
isFocusable = PR_TRUE;
|
||||
nsCOMPtr<nsIContentViewer> zombieViewer;
|
||||
contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
|
||||
if (zombieViewer) {
|
||||
// If there are 2 viewers for the current docshell, that
|
||||
// means the current document is a zombie document.
|
||||
// Only navigate into the frame/iframe if it's not a zombie.
|
||||
isFocusable = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFocusable && aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
return isFocusable;
|
||||
}
|
||||
|
||||
void
|
||||
nsGenericHTMLFormElement::SetParent(nsIContent* aParent)
|
||||
{
|
||||
|
@ -3623,17 +3660,47 @@ nsGenericHTMLElement::Focus()
|
|||
{
|
||||
// Generic HTML elements are focusable only if
|
||||
// tabindex explicitly set and tabindex >= 0
|
||||
nsAutoString tabIndexStr;
|
||||
GetAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex, tabIndexStr);
|
||||
if (!tabIndexStr.IsEmpty()) {
|
||||
PRInt32 rv, tabIndexVal = tabIndexStr.ToInteger(&rv);
|
||||
if (NS_SUCCEEDED(rv) && tabIndexVal >= 0) {
|
||||
SetElementFocus(PR_TRUE);
|
||||
return NS_OK;
|
||||
}
|
||||
if (IsFocusable()) {
|
||||
SetElementFocus(PR_TRUE);
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsGenericHTMLElement::RemoveFocus(nsIPresContext *aPresContext)
|
||||
{
|
||||
if (!aPresContext)
|
||||
return;
|
||||
|
||||
if (IsContentOfType(eHTML_FORM_CONTROL)) {
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
|
||||
if (formControlFrame) {
|
||||
formControlFrame->SetFocus(PR_FALSE, PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDocument) {
|
||||
aPresContext->EventStateManager()->SetContentState(nsnull,
|
||||
NS_EVENT_STATE_FOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsGenericHTMLElement::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
PRInt32 tabIndex = 0; // Default value for non HTML elements with -moz-user-focus
|
||||
GetTabIndex(&tabIndex);
|
||||
// Just check for disabled attribute on all HTML elements
|
||||
if (HasAttr(kNameSpaceID_None, nsHTMLAtoms::disabled)) {
|
||||
tabIndex = -1;
|
||||
}
|
||||
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = tabIndex;
|
||||
}
|
||||
|
||||
return tabIndex >= 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -189,6 +189,8 @@ public:
|
|||
virtual void DumpContent(FILE* out, PRInt32 aIndent,PRBool aDumpAll) const;
|
||||
#endif
|
||||
virtual PRBool IsContentOfType(PRUint32 aFlags) const;
|
||||
virtual void RemoveFocus(nsIPresContext *aPresContext);
|
||||
virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
|
||||
nsresult HandleDOMEvent(nsIPresContext* aPresContext,
|
||||
nsEvent* aEvent,
|
||||
|
@ -945,6 +947,7 @@ public:
|
|||
NS_IMETHOD SetFrameLoader(nsIFrameLoader *aFrameLoader);
|
||||
|
||||
// nsIContent
|
||||
virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
virtual void SetParent(nsIContent *aParent);
|
||||
virtual void SetDocument(nsIDocument *aDocument, PRBool aDeep,
|
||||
PRBool aCompileEventHandlers);
|
||||
|
|
|
@ -102,7 +102,8 @@ public:
|
|||
virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep,
|
||||
PRBool aCompileEventHandlers);
|
||||
virtual void SetFocus(nsIPresContext* aPresContext);
|
||||
virtual void RemoveFocus(nsIPresContext* aPresContext);
|
||||
virtual PRBool IsFocusable(PRBool *aTabIndex = nsnull);
|
||||
|
||||
virtual nsresult HandleDOMEvent(nsIPresContext* aPresContext,
|
||||
nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
|
||||
PRUint32 aFlags,
|
||||
|
@ -234,20 +235,30 @@ nsHTMLAnchorElement::SetFocus(nsIPresContext* aPresContext)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLAnchorElement::RemoveFocus(nsIPresContext* aPresContext)
|
||||
PRBool
|
||||
nsHTMLAnchorElement::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
if (!aPresContext) {
|
||||
return;
|
||||
if (!nsGenericHTMLElement::IsFocusable(aTabIndex)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// If we are disabled, we probably shouldn't have focus in the
|
||||
// first place, so allow it to be removed.
|
||||
|
||||
if (mDocument) {
|
||||
aPresContext->EventStateManager()->SetContentState(nsnull,
|
||||
NS_EVENT_STATE_FOCUS);
|
||||
PRBool isFocusable = PR_FALSE;
|
||||
nsAutoString href;
|
||||
GetAttribute(NS_LITERAL_STRING("href"), href);
|
||||
if (href.IsEmpty() && !HasAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex)) {
|
||||
// Not tabbable or focusable without href (bug 17605), unless
|
||||
// forced to be via presence of nonnegative tabindex attribute
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (aTabIndex && (sTabFocusModel & eTabFocus_linksMask) == 0) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -88,7 +88,6 @@ public:
|
|||
PRUint32 aFlags,
|
||||
nsEventStatus* aEventStatus);
|
||||
virtual void SetFocus(nsIPresContext* aPresContext);
|
||||
virtual void RemoveFocus(nsIPresContext* aPresContext);
|
||||
|
||||
virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep,
|
||||
PRBool aCompileEventHandlers);
|
||||
|
@ -202,16 +201,6 @@ nsHTMLAreaElement::SetFocus(nsIPresContext* aPresContext)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLAreaElement::RemoveFocus(nsIPresContext* aPresContext)
|
||||
{
|
||||
if (!aPresContext)
|
||||
return;
|
||||
|
||||
aPresContext->EventStateManager()->SetContentState(nsnull,
|
||||
NS_EVENT_STATE_FOCUS);
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLAreaElement::SetDocument(nsIDocument* aDocument, PRBool aDeep,
|
||||
PRBool aCompileEventHandlers)
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
|
||||
// nsIContent overrides...
|
||||
virtual void SetFocus(nsIPresContext* aPresContext);
|
||||
virtual void RemoveFocus(nsIPresContext* aPresContext);
|
||||
virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
virtual PRBool ParseAttribute(nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult);
|
||||
|
@ -219,6 +219,18 @@ nsHTMLButtonElement::Click()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLButtonElement::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
if (!nsGenericHTMLElement::IsFocusable(aTabIndex)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (aTabIndex && (sTabFocusModel & eTabFocus_formElementsMask) == 0) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonElement::SetFocus(nsIPresContext* aPresContext)
|
||||
{
|
||||
|
@ -241,26 +253,6 @@ nsHTMLButtonElement::SetFocus(nsIPresContext* aPresContext)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonElement::RemoveFocus(nsIPresContext* aPresContext)
|
||||
{
|
||||
if (!aPresContext)
|
||||
return;
|
||||
|
||||
// If we are disabled, we probably shouldn't have focus in the
|
||||
// first place, so allow it to be removed.
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
|
||||
|
||||
if (formControlFrame) {
|
||||
formControlFrame->SetFocus(PR_FALSE, PR_FALSE);
|
||||
}
|
||||
|
||||
if (mDocument) {
|
||||
aPresContext->EventStateManager()->SetContentState(nsnull,
|
||||
NS_EVENT_STATE_FOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
static const nsHTMLValue::EnumTable kButtonTypeTable[] = {
|
||||
{ "button", NS_FORM_BUTTON_BUTTON },
|
||||
{ "reset", NS_FORM_BUTTON_RESET },
|
||||
|
|
|
@ -77,6 +77,8 @@
|
|||
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsImageMapUtils.h"
|
||||
#include "nsIDOMHTMLMapElement.h"
|
||||
|
||||
// XXX nav attrs: suppress
|
||||
|
||||
|
@ -128,6 +130,7 @@ public:
|
|||
nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
|
||||
PRUint32 aFlags,
|
||||
nsEventStatus* aEventStatus);
|
||||
PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
|
||||
// SetAttr override. C++ is stupid, so have to override both
|
||||
// overloaded methods.
|
||||
|
@ -527,6 +530,34 @@ nsHTMLImageElement::HandleDOMEvent(nsIPresContext* aPresContext,
|
|||
aFlags, aEventStatus);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLImageElement::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
PRInt32 tabIndex;
|
||||
GetTabIndex(&tabIndex);
|
||||
|
||||
if (mDocument) {
|
||||
nsAutoString usemap;
|
||||
GetUseMap(usemap);
|
||||
nsCOMPtr<nsIDOMHTMLMapElement> imageMap =
|
||||
nsImageMapUtils::FindImageMap(mDocument, usemap);
|
||||
if (imageMap) {
|
||||
if (aTabIndex) {
|
||||
// Use tab index on individual map areas
|
||||
*aTabIndex = (sTabFocusModel & eTabFocus_linksMask)? 0 : -1;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTabIndex) {
|
||||
// Can be in tab order if tabindex >=0 and form controls are tabbable.
|
||||
*aTabIndex = (sTabFocusModel & eTabFocus_formElementsMask)? tabIndex : -1;
|
||||
}
|
||||
|
||||
return tabIndex >= 0;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLImageElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
|
|
|
@ -175,7 +175,7 @@ public:
|
|||
|
||||
// nsIContent
|
||||
virtual void SetFocus(nsIPresContext* aPresContext);
|
||||
virtual void RemoveFocus(nsIPresContext* aPresContext);
|
||||
virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
|
||||
virtual PRBool ParseAttribute(nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
|
@ -1081,27 +1081,6 @@ nsHTMLInputElement::SetFocus(nsIPresContext* aPresContext)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLInputElement::RemoveFocus(nsIPresContext* aPresContext)
|
||||
{
|
||||
if (!aPresContext)
|
||||
return;
|
||||
|
||||
// If we are disabled, we probably shouldn't have focus in the
|
||||
// first place, so allow it to be removed.
|
||||
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
|
||||
|
||||
if (formControlFrame) {
|
||||
formControlFrame->SetFocus(PR_FALSE, PR_FALSE);
|
||||
}
|
||||
|
||||
if (mDocument) {
|
||||
aPresContext->EventStateManager()->SetContentState(nsnull,
|
||||
NS_EVENT_STATE_FOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::Select()
|
||||
{
|
||||
|
@ -2633,43 +2612,45 @@ nsHTMLInputElement::WillRemoveFromRadioGroup()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLInputElement::GetTabbable(PRBool *isTabbable)
|
||||
PRBool
|
||||
nsHTMLInputElement::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
*isTabbable = PR_TRUE;
|
||||
|
||||
PRBool disabled;
|
||||
GetDisabled(&disabled);
|
||||
// XXX aaronlev: when fix for bug 171366 goes in we'll need to check
|
||||
// for negative tabIndex, which indicates something is not tabbable.
|
||||
// PRInt32 tabIndex;
|
||||
// GetTabIndex(&tabIndex);
|
||||
|
||||
if (disabled || /* tabIndex < 0 || */ mType == NS_FORM_INPUT_HIDDEN ||
|
||||
mType == NS_FORM_INPUT_FILE) {
|
||||
// Sub controls of file input are tabbable, not the file input itself.
|
||||
*isTabbable = PR_FALSE;
|
||||
return NS_OK;
|
||||
if (!nsGenericHTMLElement::IsFocusable(aTabIndex)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (mType != NS_FORM_INPUT_TEXT && mType != NS_FORM_INPUT_PASSWORD) {
|
||||
nsCOMPtr<nsIPresContext> presContext;
|
||||
GetPresContext(this, getter_AddRefs(presContext));
|
||||
if (presContext) {
|
||||
nsIEventStateManager *esm = presContext->EventStateManager();
|
||||
esm->GetTabbable(eTabFocus_formElementsMask, isTabbable);
|
||||
if (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (mType == NS_FORM_INPUT_HIDDEN || mType == NS_FORM_INPUT_FILE) {
|
||||
// Sub controls of file input are tabbable, not the file input itself.
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!aTabIndex) {
|
||||
// The other controls are all focusable
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// We need to set tabindex to -1 if we're not tabbable
|
||||
if (mType != NS_FORM_INPUT_TEXT && mType != NS_FORM_INPUT_PASSWORD &&
|
||||
!(sTabFocusModel & eTabFocus_formElementsMask)) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
if (mType != NS_FORM_INPUT_RADIO) {
|
||||
return NS_OK;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool checked;
|
||||
GetChecked(&checked);
|
||||
if (checked) {
|
||||
// Selected radio buttons are tabbable
|
||||
return NS_OK;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Current radio button is not selected.
|
||||
|
@ -2677,16 +2658,15 @@ nsHTMLInputElement::GetTabbable(PRBool *isTabbable)
|
|||
nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
|
||||
nsAutoString name;
|
||||
if (!container || !GetNameIfExists(name)) {
|
||||
return NS_OK;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> currentRadio;
|
||||
container->GetCurrentRadioButton(name, getter_AddRefs(currentRadio));
|
||||
if (currentRadio) {
|
||||
*isTabbable = PR_FALSE;
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -70,6 +70,9 @@ public:
|
|||
// nsIDOMHTMLObjectElement
|
||||
NS_DECL_NSIDOMHTMLOBJECTELEMENT
|
||||
|
||||
// nsIContent
|
||||
virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
|
||||
// Overriden nsIFormControl methods
|
||||
NS_IMETHOD_(PRInt32) GetType() { return NS_FORM_OBJECT; }
|
||||
NS_IMETHOD Reset();
|
||||
|
@ -145,6 +148,18 @@ nsHTMLObjectElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
|||
return nsGenericHTMLFormElement::GetForm(aForm);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLObjectElement::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
if (!nsGenericHTMLElement::IsFocusable(aTabIndex)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (aTabIndex && (sTabFocusModel & eTabFocus_formElementsMask) == 0) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// nsIFormControl
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -223,7 +223,7 @@ public:
|
|||
nsEventStatus* aEventStatus);
|
||||
|
||||
virtual void SetFocus(nsIPresContext* aPresContext);
|
||||
virtual void RemoveFocus(nsIPresContext* aPresContext);
|
||||
virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
|
||||
// Overriden nsIFormControl methods
|
||||
NS_IMETHOD_(PRInt32) GetType() { return NS_FORM_SELECT; }
|
||||
|
@ -1620,25 +1620,16 @@ nsHTMLSelectElement::SetFocus(nsIPresContext* aPresContext)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLSelectElement::RemoveFocus(nsIPresContext* aPresContext)
|
||||
PRBool
|
||||
nsHTMLSelectElement::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
if (!aPresContext)
|
||||
return;
|
||||
|
||||
// If we are disabled, we probably shouldn't have focus in the
|
||||
// first place, so allow it to be removed.
|
||||
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
|
||||
|
||||
if (formControlFrame) {
|
||||
formControlFrame->SetFocus(PR_FALSE, PR_FALSE);
|
||||
if (!nsGenericHTMLElement::IsFocusable(aTabIndex)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (mDocument) {
|
||||
aPresContext->EventStateManager()->SetContentState(nsnull,
|
||||
NS_EVENT_STATE_FOCUS);
|
||||
if (aTabIndex && (sTabFocusModel & eTabFocus_formElementsMask) == 0) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -130,7 +130,6 @@ public:
|
|||
PRUint32 aFlags,
|
||||
nsEventStatus* aEventStatus);
|
||||
virtual void SetFocus(nsIPresContext* aPresContext);
|
||||
virtual void RemoveFocus(nsIPresContext* aPresContext);
|
||||
|
||||
virtual nsresult GetInnerHTML(nsAString& aInnerHTML);
|
||||
virtual nsresult SetInnerHTML(const nsAString& aInnerHTML);
|
||||
|
@ -260,27 +259,6 @@ nsHTMLTextAreaElement::SetFocus(nsIPresContext* aPresContext)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLTextAreaElement::RemoveFocus(nsIPresContext* aPresContext)
|
||||
{
|
||||
if (!aPresContext)
|
||||
return;
|
||||
|
||||
// If we are disabled, we probably shouldn't have focus in the
|
||||
// first place, so allow it to be removed.
|
||||
|
||||
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
|
||||
|
||||
if (formControlFrame) {
|
||||
formControlFrame->SetFocus(PR_FALSE, PR_FALSE);
|
||||
}
|
||||
|
||||
if (mDocument) {
|
||||
aPresContext->EventStateManager()->SetContentState(nsnull,
|
||||
NS_EVENT_STATE_FOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLTextAreaElement::Select()
|
||||
{
|
||||
|
|
|
@ -147,6 +147,7 @@
|
|||
#include "nsDOMAttributeMap.h"
|
||||
#include "nsDOMCSSDeclaration.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#include "rdf.h"
|
||||
|
@ -1424,6 +1425,32 @@ nsXULElement::GetListenerManager(nsIEventListenerManager** aResult)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsXULElement::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
// Use incoming tabindex as default value
|
||||
PRInt32 tabIndex = aTabIndex? *aTabIndex : -1;
|
||||
PRBool disabled = tabIndex < 0;
|
||||
nsCOMPtr<nsIDOMXULControlElement> xulControl =
|
||||
do_QueryInterface(NS_STATIC_CAST(nsIContent*, this));
|
||||
if (xulControl) {
|
||||
xulControl->GetDisabled(&disabled);
|
||||
if (disabled) {
|
||||
tabIndex = -1; // Can't tab to disabled elements
|
||||
}
|
||||
else if (HasAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex)) {
|
||||
// If attribute not set, will use default value passed in
|
||||
xulControl->GetTabIndex(&tabIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = tabIndex;
|
||||
}
|
||||
|
||||
return !disabled;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsIScriptEventHandlerOwner interface
|
||||
|
|
|
@ -493,6 +493,7 @@ public:
|
|||
virtual PRBool IsContentOfType(PRUint32 aFlags) const;
|
||||
virtual already_AddRefed<nsIURI> GetBaseURI() const;
|
||||
virtual nsresult GetListenerManager(nsIEventListenerManager** aResult);
|
||||
virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
|
||||
// nsIXMLContent
|
||||
NS_IMETHOD MaybeTriggerAutoLink(nsIDocShell *aShell);
|
||||
|
|
|
@ -58,9 +58,4 @@ interface nsIDOMNSHTMLInputElement : nsISupports
|
|||
/* convenience */
|
||||
void setSelectionRange(in long selectionStart,
|
||||
in long selectionEnd);
|
||||
|
||||
/**
|
||||
* Is this input control in the tab order?
|
||||
*/
|
||||
readonly attribute boolean tabbable;
|
||||
};
|
||||
|
|
|
@ -1240,6 +1240,26 @@ NS_PTR_TO_INT32(frame->GetProperty(nsLayoutAtoms::embeddingLevel))
|
|||
*/
|
||||
virtual PRBool SupportsVisibilityHidden() { return PR_TRUE; }
|
||||
|
||||
/**
|
||||
* Check if this frame is focusable and in the current tab order.
|
||||
* Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
|
||||
* For example, only the selected radio button in a group is in the
|
||||
* tab order, unless the radio group has no selection in which case
|
||||
* all of the visible, non-disabled radio buttons in the group are
|
||||
* in the tab order. On the other hand, all of the visible, non-disabled
|
||||
* radio buttons are always focusable via clicking or script.
|
||||
* Also, depending on the pref accessibility.tabfocus some widgets may be
|
||||
* focusable but removed from the tab order. This is the default on
|
||||
* Mac OS X, where fewer items are focusable.
|
||||
* @param [in, optional] aTabIndex the computed tab index
|
||||
* < 0 if not tabbable
|
||||
* == 0 if in normal tab order
|
||||
* > 0 can be tabbed to in the order specified by this value
|
||||
* @return whether the frame is focusable via mouse, kbd or script.
|
||||
*/
|
||||
PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
static nsIFrame *FocusableAncestor(nsIFrame *aFrame);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
nsRect mRect;
|
||||
|
|
|
@ -4618,6 +4618,59 @@ nsFrame::GetStyleDataExternal(nsStyleStructID aSID) const
|
|||
return mStyleContext->GetStyleData(aSID);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsIFrame::FocusableAncestor(nsIFrame *aFrame)
|
||||
{
|
||||
// This method helps prevent a situation where a link or other element
|
||||
// with -moz-user-focus is focused twice, because the parent link
|
||||
// would get focused, and all of the children also get focus.
|
||||
// Scroll frames are the only focusable containers that
|
||||
// can have focusable children.
|
||||
|
||||
nsIFrame *ancestorFrame = aFrame;
|
||||
while ((ancestorFrame = ancestorFrame->GetParent()) != nsnull &&
|
||||
ancestorFrame->GetType() != nsLayoutAtoms::scrollFrame) {
|
||||
// Any other parent that's focusable can't have focusable children
|
||||
const nsStyleUserInterface *ui = ancestorFrame->GetStyleUserInterface();
|
||||
if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
|
||||
ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
|
||||
// Inside a focusable parent -- let parent get focus
|
||||
// instead of child (to avoid links within links etc.)
|
||||
return ancestorFrame;
|
||||
}
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsIFrame::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
PRInt32 tabIndex = -1;
|
||||
PRBool isFocusable = PR_FALSE;
|
||||
|
||||
if (AreAncestorViewsVisible() && mContent &&
|
||||
mContent->IsContentOfType(nsIContent::eELEMENT) &&
|
||||
!FocusableAncestor(this)) {
|
||||
const nsStyleVisibility* vis = GetStyleVisibility();
|
||||
if (vis->mVisible != NS_STYLE_VISIBILITY_COLLAPSE &&
|
||||
vis->mVisible != NS_STYLE_VISIBILITY_HIDDEN) {
|
||||
const nsStyleUserInterface* ui = GetStyleUserInterface();
|
||||
if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
|
||||
ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
|
||||
// Pass in default tabindex of -1 for nonfocusable and 0 for focusable
|
||||
tabIndex = 0;
|
||||
}
|
||||
isFocusable = mContent->IsFocusable(&tabIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = tabIndex;
|
||||
}
|
||||
return isFocusable;
|
||||
}
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
static void
|
||||
GetTagName(nsFrame* aFrame, nsIContent* aContent, PRIntn aResultSize,
|
||||
|
|
|
@ -1240,6 +1240,26 @@ NS_PTR_TO_INT32(frame->GetProperty(nsLayoutAtoms::embeddingLevel))
|
|||
*/
|
||||
virtual PRBool SupportsVisibilityHidden() { return PR_TRUE; }
|
||||
|
||||
/**
|
||||
* Check if this frame is focusable and in the current tab order.
|
||||
* Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
|
||||
* For example, only the selected radio button in a group is in the
|
||||
* tab order, unless the radio group has no selection in which case
|
||||
* all of the visible, non-disabled radio buttons in the group are
|
||||
* in the tab order. On the other hand, all of the visible, non-disabled
|
||||
* radio buttons are always focusable via clicking or script.
|
||||
* Also, depending on the pref accessibility.tabfocus some widgets may be
|
||||
* focusable but removed from the tab order. This is the default on
|
||||
* Mac OS X, where fewer items are focusable.
|
||||
* @param [in, optional] aTabIndex the computed tab index
|
||||
* < 0 if not tabbable
|
||||
* == 0 if in normal tab order
|
||||
* > 0 can be tabbed to in the order specified by this value
|
||||
* @return whether the frame is focusable via mouse, kbd or script.
|
||||
*/
|
||||
PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
|
||||
static nsIFrame *FocusableAncestor(nsIFrame *aFrame);
|
||||
|
||||
protected:
|
||||
// Members
|
||||
nsRect mRect;
|
||||
|
|
|
@ -4618,6 +4618,59 @@ nsFrame::GetStyleDataExternal(nsStyleStructID aSID) const
|
|||
return mStyleContext->GetStyleData(aSID);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsIFrame::FocusableAncestor(nsIFrame *aFrame)
|
||||
{
|
||||
// This method helps prevent a situation where a link or other element
|
||||
// with -moz-user-focus is focused twice, because the parent link
|
||||
// would get focused, and all of the children also get focus.
|
||||
// Scroll frames are the only focusable containers that
|
||||
// can have focusable children.
|
||||
|
||||
nsIFrame *ancestorFrame = aFrame;
|
||||
while ((ancestorFrame = ancestorFrame->GetParent()) != nsnull &&
|
||||
ancestorFrame->GetType() != nsLayoutAtoms::scrollFrame) {
|
||||
// Any other parent that's focusable can't have focusable children
|
||||
const nsStyleUserInterface *ui = ancestorFrame->GetStyleUserInterface();
|
||||
if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
|
||||
ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
|
||||
// Inside a focusable parent -- let parent get focus
|
||||
// instead of child (to avoid links within links etc.)
|
||||
return ancestorFrame;
|
||||
}
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsIFrame::IsFocusable(PRInt32 *aTabIndex)
|
||||
{
|
||||
PRInt32 tabIndex = -1;
|
||||
PRBool isFocusable = PR_FALSE;
|
||||
|
||||
if (AreAncestorViewsVisible() && mContent &&
|
||||
mContent->IsContentOfType(nsIContent::eELEMENT) &&
|
||||
!FocusableAncestor(this)) {
|
||||
const nsStyleVisibility* vis = GetStyleVisibility();
|
||||
if (vis->mVisible != NS_STYLE_VISIBILITY_COLLAPSE &&
|
||||
vis->mVisible != NS_STYLE_VISIBILITY_HIDDEN) {
|
||||
const nsStyleUserInterface* ui = GetStyleUserInterface();
|
||||
if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
|
||||
ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
|
||||
// Pass in default tabindex of -1 for nonfocusable and 0 for focusable
|
||||
tabIndex = 0;
|
||||
}
|
||||
isFocusable = mContent->IsFocusable(&tabIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = tabIndex;
|
||||
}
|
||||
return isFocusable;
|
||||
}
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
static void
|
||||
GetTagName(nsFrame* aFrame, nsIContent* aContent, PRIntn aResultSize,
|
||||
|
|
|
@ -408,8 +408,20 @@ noframes {
|
|||
display: none;
|
||||
}
|
||||
|
||||
*|*:-moz-any-link:focus img {
|
||||
-moz-outline: 1px dotted invert;
|
||||
}
|
||||
|
||||
*|*:-moz-any-link:focus object {
|
||||
-moz-outline: 1px dotted invert;
|
||||
}
|
||||
|
||||
*|*:-moz-any-link:focus embed {
|
||||
-moz-outline: 1px dotted invert;
|
||||
}
|
||||
|
||||
/* focusable content: anything w/ tabindex >=0 is focusable */
|
||||
a:focus, abbr:focus, acronym:focus, address:focus, applet:focus, b:focus,
|
||||
abbr:focus, acronym:focus, address:focus, applet:focus, b:focus,
|
||||
base:focus, big:focus, blockquote:focus, br:focus, caption:focus, center:focus,
|
||||
cite:focus, code:focus, col:focus, colgroup:focus, dd:focus, del:focus,
|
||||
dfn:focus, dir:focus, div:focus, dl:focus, dt:focus, em:focus, fieldset:focus,
|
||||
|
|
|
@ -408,8 +408,20 @@ noframes {
|
|||
display: none;
|
||||
}
|
||||
|
||||
*|*:-moz-any-link:focus img {
|
||||
-moz-outline: 1px dotted invert;
|
||||
}
|
||||
|
||||
*|*:-moz-any-link:focus object {
|
||||
-moz-outline: 1px dotted invert;
|
||||
}
|
||||
|
||||
*|*:-moz-any-link:focus embed {
|
||||
-moz-outline: 1px dotted invert;
|
||||
}
|
||||
|
||||
/* focusable content: anything w/ tabindex >=0 is focusable */
|
||||
a:focus, abbr:focus, acronym:focus, address:focus, applet:focus, b:focus,
|
||||
abbr:focus, acronym:focus, address:focus, applet:focus, b:focus,
|
||||
base:focus, big:focus, blockquote:focus, br:focus, caption:focus, center:focus,
|
||||
cite:focus, code:focus, col:focus, colgroup:focus, dd:focus, del:focus,
|
||||
dfn:focus, dir:focus, div:focus, dl:focus, dt:focus, em:focus, fieldset:focus,
|
||||
|
|
Загрузка…
Ссылка в новой задаче