зеркало из https://github.com/mozilla/pjs.git
Bug 426082, part 3: Reflect a label's :hover/:active state on its associated natively themed control.
This patch adds an aFollowLabels argument to nsIEventStateManager::GetContentState which defaults to false. Setting it to true will return NS_EVENT_STATE_HOVER / _ACTIVE for labeled controls even if only their label is subject to this state. At the moment this flag is only set by native theming, so there won't be an observable change for the :hover / :active pseudoclasses. In order to make dynamic state changes on the label work, SetContentState will now always notify the labeled control of state changes when its label changes state. r=smaug
This commit is contained in:
Родитель
65469b4a69
Коммит
adb70d0cbc
|
@ -85,7 +85,18 @@ public:
|
|||
NS_IMETHOD GetEventTarget(nsIFrame **aFrame) = 0;
|
||||
NS_IMETHOD GetEventTargetContent(nsEvent* aEvent, nsIContent** aContent) = 0;
|
||||
|
||||
virtual PRInt32 GetContentState(nsIContent *aContent) = 0;
|
||||
/**
|
||||
* Returns the content state of aContent.
|
||||
* @param aContent The control whose state is requested.
|
||||
* @param aFollowLabels Whether to reflect a label's content state on its
|
||||
* associated control. If aFollowLabels is true and
|
||||
* aContent is a control which has a label that has the
|
||||
* hover or active content state set, GetContentState
|
||||
* will pretend that those states are also set on aContent.
|
||||
* @return The content state.
|
||||
*/
|
||||
virtual PRInt32 GetContentState(nsIContent *aContent,
|
||||
PRBool aFollowLabels = PR_FALSE) = 0;
|
||||
|
||||
/**
|
||||
* Notify that the given NS_EVENT_STATE_* bit has changed for this content.
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#include "nsIDOMHTMLAnchorElement.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "nsIDOMNSHTMLInputElement.h"
|
||||
#include "nsIDOMNSHTMLLabelElement.h"
|
||||
#include "nsIDOMHTMLSelectElement.h"
|
||||
#include "nsIDOMHTMLTextAreaElement.h"
|
||||
#include "nsIDOMHTMLAreaElement.h"
|
||||
|
@ -3977,25 +3978,48 @@ nsEventStateManager::GetEventTargetContent(nsEvent* aEvent,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIContent>
|
||||
GetLabelTarget(nsIContent* aLabel)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNSHTMLLabelElement> label = do_QueryInterface(aLabel);
|
||||
if (!label)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLElement> target;
|
||||
label->GetControl(getter_AddRefs(target));
|
||||
nsIContent* targetContent = nsnull;
|
||||
if (target) {
|
||||
CallQueryInterface(target, &targetContent);
|
||||
}
|
||||
return targetContent;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsAncestorOf(nsIContent* aPossibleAncestor, nsIContent* aPossibleDescendant)
|
||||
IsAncestorOf(nsIContent* aPossibleAncestor, nsIContent* aPossibleDescendant,
|
||||
PRBool aFollowLabels)
|
||||
{
|
||||
for (; aPossibleDescendant; aPossibleDescendant = aPossibleDescendant->GetParent()) {
|
||||
if (aPossibleAncestor == aPossibleDescendant)
|
||||
return true;
|
||||
|
||||
if (aFollowLabels) {
|
||||
nsCOMPtr<nsIContent> labelTarget = GetLabelTarget(aPossibleDescendant);
|
||||
if (labelTarget == aPossibleAncestor)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsEventStateManager::GetContentState(nsIContent *aContent)
|
||||
nsEventStateManager::GetContentState(nsIContent *aContent, PRBool aFollowLabels)
|
||||
{
|
||||
PRInt32 state = aContent->IntrinsicState();
|
||||
|
||||
if (IsAncestorOf(aContent, mActiveContent)) {
|
||||
if (IsAncestorOf(aContent, mActiveContent, aFollowLabels)) {
|
||||
state |= NS_EVENT_STATE_ACTIVE;
|
||||
}
|
||||
if (IsAncestorOf(aContent, mHoverContent)) {
|
||||
if (IsAncestorOf(aContent, mHoverContent, aFollowLabels)) {
|
||||
state |= NS_EVENT_STATE_HOVER;
|
||||
}
|
||||
|
||||
|
@ -4071,6 +4095,10 @@ NotifyAncestors(nsIDocument* aDocument, nsIContent* aStartNode,
|
|||
{
|
||||
while (aStartNode && aStartNode != aStopBefore) {
|
||||
aDocument->ContentStatesChanged(aStartNode, nsnull, aState);
|
||||
nsCOMPtr<nsIContent> labelTarget = GetLabelTarget(aStartNode);
|
||||
if (labelTarget) {
|
||||
aDocument->ContentStatesChanged(labelTarget, nsnull, aState);
|
||||
}
|
||||
aStartNode = aStartNode->GetParent();
|
||||
}
|
||||
}
|
||||
|
@ -4281,14 +4309,14 @@ nsEventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent
|
|||
nsContentUtils::ContentIsDescendantOf(mHoverContent, aContent)) {
|
||||
// Since hover is hierarchical, set the current hover to the
|
||||
// content's parent node.
|
||||
mHoverContent = aContent->GetParent();
|
||||
SetContentState(aContent->GetParent(), NS_EVENT_STATE_HOVER);
|
||||
}
|
||||
|
||||
if (mActiveContent &&
|
||||
nsContentUtils::ContentIsDescendantOf(mActiveContent, aContent)) {
|
||||
// Active is hierarchical, so set the current active to the
|
||||
// content's parent node.
|
||||
mActiveContent = aContent->GetParent();
|
||||
SetContentState(aContent->GetParent(), NS_EVENT_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
if (mDragOverContent &&
|
||||
|
|
|
@ -120,7 +120,8 @@ public:
|
|||
NS_IMETHOD GetEventTarget(nsIFrame **aFrame);
|
||||
NS_IMETHOD GetEventTargetContent(nsEvent* aEvent, nsIContent** aContent);
|
||||
|
||||
virtual PRInt32 GetContentState(nsIContent *aContent);
|
||||
virtual PRInt32 GetContentState(nsIContent *aContent,
|
||||
PRBool aFollowLabels = PR_FALSE);
|
||||
virtual PRBool SetContentState(nsIContent *aContent, PRInt32 aState);
|
||||
NS_IMETHOD ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
|
||||
NS_IMETHOD EventStatusOK(nsGUIEvent* aEvent, PRBool *aOK);
|
||||
|
|
|
@ -90,7 +90,7 @@ nsNativeTheme::GetContentState(nsIFrame* aFrame, PRUint8 aWidgetType)
|
|||
return 0;
|
||||
|
||||
nsIEventStateManager* esm = shell->GetPresContext()->EventStateManager();
|
||||
PRInt32 flags = esm->GetContentState(aFrame->GetContent());
|
||||
PRInt32 flags = esm->GetContentState(aFrame->GetContent(), PR_TRUE);
|
||||
|
||||
if (isXULCheckboxRadio && aWidgetType == NS_THEME_RADIO) {
|
||||
if (IsFocused(aFrame))
|
||||
|
|
Загрузка…
Ссылка в новой задаче