mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 1323618 - Allow locking off of psuedo-classes through inIDOMUtils. r=heycam
MozReview-Commit-ID: DppYTmILpwy --HG-- extra : rebase_source : c0befc8f86b92cfc88b537e520c3aa032846ba6a
This commit is contained in:
parent
90c9daf114
commit
072c1a6ba3
@ -1755,6 +1755,8 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||||||
* Options object:
|
* Options object:
|
||||||
* `parents`: True if the pseudo-class should be added
|
* `parents`: True if the pseudo-class should be added
|
||||||
* to parent nodes.
|
* to parent nodes.
|
||||||
|
* `enabled`: False if the pseudo-class should be locked
|
||||||
|
* to 'off'. Defaults to true.
|
||||||
*
|
*
|
||||||
* @returns An empty packet. A "pseudoClassLock" mutation will
|
* @returns An empty packet. A "pseudoClassLock" mutation will
|
||||||
* be queued for any changed nodes.
|
* be queued for any changed nodes.
|
||||||
@ -1772,7 +1774,9 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._addPseudoClassLock(node, pseudo);
|
let enabled = options.enabled === undefined ||
|
||||||
|
options.enabled;
|
||||||
|
this._addPseudoClassLock(node, pseudo, enabled);
|
||||||
|
|
||||||
if (!options.parents) {
|
if (!options.parents) {
|
||||||
return;
|
return;
|
||||||
@ -1782,7 +1786,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||||||
let cur;
|
let cur;
|
||||||
while ((cur = walker.parentNode())) {
|
while ((cur = walker.parentNode())) {
|
||||||
let curNode = this._ref(cur);
|
let curNode = this._ref(cur);
|
||||||
this._addPseudoClassLock(curNode, pseudo);
|
this._addPseudoClassLock(curNode, pseudo, enabled);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1794,11 +1798,11 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_addPseudoClassLock: function (node, pseudo) {
|
_addPseudoClassLock: function (node, pseudo, enabled) {
|
||||||
if (node.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
|
if (node.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DOMUtils.addPseudoClassLock(node.rawNode, pseudo);
|
DOMUtils.addPseudoClassLock(node.rawNode, pseudo, enabled);
|
||||||
this._activePseudoClassLocks.add(node);
|
this._activePseudoClassLocks.add(node);
|
||||||
this._queuePseudoClassMutation(node);
|
this._queuePseudoClassMutation(node);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
@ -60,16 +60,21 @@ function checkChange(change, expectation) {
|
|||||||
|
|
||||||
is(target.pseudoClassLocks.length, expectation.pseudos.length,
|
is(target.pseudoClassLocks.length, expectation.pseudos.length,
|
||||||
"Expect " + expectation.pseudos.length + " pseudoclass locks.");
|
"Expect " + expectation.pseudos.length + " pseudoclass locks.");
|
||||||
for (let pseudo of expectation.pseudos) {
|
for (let i = 0; i < expectation.pseudos.length; i++) {
|
||||||
|
let pseudo = expectation.pseudos[i];
|
||||||
|
let enabled = expectation.enabled === undefined ? true : expectation.enabled[i];
|
||||||
ok(target.hasPseudoClassLock(pseudo), "Expect lock: " + pseudo);
|
ok(target.hasPseudoClassLock(pseudo), "Expect lock: " + pseudo);
|
||||||
ok(DOMUtils.hasPseudoClassLock(target.rawNode(), pseudo), "Expect lock in dom: " + pseudo);
|
let rawNode = target.rawNode();
|
||||||
|
ok(DOMUtils.hasPseudoClassLock(rawNode, pseudo), "Expect lock in dom: " + pseudo);
|
||||||
|
|
||||||
|
is(rawNode.matches(pseudo), enabled,
|
||||||
|
`Target should match pseudoclass, '${pseudo}', if enabled (with .matches())`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let pseudo of KNOWN_PSEUDOCLASSES) {
|
for (let pseudo of KNOWN_PSEUDOCLASSES) {
|
||||||
if (!expectation.pseudos.some(expected => pseudo === expected)) {
|
if (!expectation.pseudos.some(expected => pseudo === expected)) {
|
||||||
ok(!target.hasPseudoClassLock(pseudo), "Don't expect lock: " + pseudo);
|
ok(!target.hasPseudoClassLock(pseudo), "Don't expect lock: " + pseudo);
|
||||||
ok(!DOMUtils.hasPseudoClassLock(target.rawNode(), pseudo), "Don't expect lock in dom: " + pseudo);
|
ok(!DOMUtils.hasPseudoClassLock(target.rawNode(), pseudo), "Don't expect lock in dom: " + pseudo);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,7 +98,7 @@ addTest(function testPseudoClassLock() {
|
|||||||
// Expect a single pseudoClassLock mutation.
|
// Expect a single pseudoClassLock mutation.
|
||||||
return promiseOnce(gWalker, "mutations");
|
return promiseOnce(gWalker, "mutations");
|
||||||
}).then(mutations => {
|
}).then(mutations => {
|
||||||
is(mutations.length, 1, "Should get one mutations");
|
is(mutations.length, 1, "Should get one mutation");
|
||||||
is(mutations[0].target, nodeFront, "Should be the node we tried to apply to");
|
is(mutations[0].target, nodeFront, "Should be the node we tried to apply to");
|
||||||
checkChange(mutations[0], {
|
checkChange(mutations[0], {
|
||||||
id: "b",
|
id: "b",
|
||||||
@ -149,6 +154,18 @@ addTest(function testPseudoClassLock() {
|
|||||||
pseudos: []
|
pseudos: []
|
||||||
}];
|
}];
|
||||||
checkMutations(mutations, expectedMutations);
|
checkMutations(mutations, expectedMutations);
|
||||||
|
}).then(() => {
|
||||||
|
gWalker.addPseudoClassLock(nodeFront, ":hover", {enabled: false});
|
||||||
|
return promiseOnce(gWalker, "mutations");
|
||||||
|
}).then(mutations => {
|
||||||
|
is(mutations.length, 1, "Should get one mutation");
|
||||||
|
is(mutations[0].target, nodeFront, "Should be the node we tried to apply to");
|
||||||
|
checkChange(mutations[0], {
|
||||||
|
id: "b",
|
||||||
|
nodeName: "DIV",
|
||||||
|
pseudos: [":hover", ":active"],
|
||||||
|
enabled: [false, true]
|
||||||
|
});
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
// Now shut down the walker and make sure that clears up the remaining lock.
|
// Now shut down the walker and make sure that clears up the remaining lock.
|
||||||
return gWalker.release();
|
return gWalker.release();
|
||||||
|
@ -234,7 +234,8 @@ const walkerSpec = generateActorSpec({
|
|||||||
request: {
|
request: {
|
||||||
node: Arg(0, "domnode"),
|
node: Arg(0, "domnode"),
|
||||||
pseudoClass: Arg(1),
|
pseudoClass: Arg(1),
|
||||||
parents: Option(2)
|
parents: Option(2),
|
||||||
|
enabled: Option(2, "boolean"),
|
||||||
},
|
},
|
||||||
response: {}
|
response: {}
|
||||||
},
|
},
|
||||||
|
@ -346,27 +346,30 @@ Element::Blur(mozilla::ErrorResult& aError)
|
|||||||
EventStates
|
EventStates
|
||||||
Element::StyleStateFromLocks() const
|
Element::StyleStateFromLocks() const
|
||||||
{
|
{
|
||||||
EventStates locks = LockedStyleStates();
|
StyleStateLocks locksAndValues = LockedStyleStates();
|
||||||
EventStates state = mState | locks;
|
EventStates locks = locksAndValues.mLocks;
|
||||||
|
EventStates values = locksAndValues.mValues;
|
||||||
|
EventStates state = (mState & ~locks) | (locks & values);
|
||||||
|
|
||||||
if (locks.HasState(NS_EVENT_STATE_VISITED)) {
|
if (state.HasState(NS_EVENT_STATE_VISITED)) {
|
||||||
return state & ~NS_EVENT_STATE_UNVISITED;
|
return state & ~NS_EVENT_STATE_UNVISITED;
|
||||||
}
|
}
|
||||||
if (locks.HasState(NS_EVENT_STATE_UNVISITED)) {
|
if (state.HasState(NS_EVENT_STATE_UNVISITED)) {
|
||||||
return state & ~NS_EVENT_STATE_VISITED;
|
return state & ~NS_EVENT_STATE_VISITED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventStates
|
Element::StyleStateLocks
|
||||||
Element::LockedStyleStates() const
|
Element::LockedStyleStates() const
|
||||||
{
|
{
|
||||||
EventStates* locks =
|
StyleStateLocks* locks =
|
||||||
static_cast<EventStates*>(GetProperty(nsGkAtoms::lockedStyleStates));
|
static_cast<StyleStateLocks*>(GetProperty(nsGkAtoms::lockedStyleStates));
|
||||||
if (locks) {
|
if (locks) {
|
||||||
return *locks;
|
return *locks;
|
||||||
}
|
}
|
||||||
return EventStates();
|
return StyleStateLocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -383,21 +386,26 @@ Element::NotifyStyleStateChange(EventStates aStates)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Element::LockStyleStates(EventStates aStates)
|
Element::LockStyleStates(EventStates aStates, bool aEnabled)
|
||||||
{
|
{
|
||||||
EventStates* locks = new EventStates(LockedStyleStates());
|
StyleStateLocks* locks = new StyleStateLocks(LockedStyleStates());
|
||||||
|
|
||||||
*locks |= aStates;
|
locks->mLocks |= aStates;
|
||||||
|
if (aEnabled) {
|
||||||
|
locks->mValues |= aStates;
|
||||||
|
} else {
|
||||||
|
locks->mValues &= ~aStates;
|
||||||
|
}
|
||||||
|
|
||||||
if (aStates.HasState(NS_EVENT_STATE_VISITED)) {
|
if (aStates.HasState(NS_EVENT_STATE_VISITED)) {
|
||||||
*locks &= ~NS_EVENT_STATE_UNVISITED;
|
locks->mLocks &= ~NS_EVENT_STATE_UNVISITED;
|
||||||
}
|
}
|
||||||
if (aStates.HasState(NS_EVENT_STATE_UNVISITED)) {
|
if (aStates.HasState(NS_EVENT_STATE_UNVISITED)) {
|
||||||
*locks &= ~NS_EVENT_STATE_VISITED;
|
locks->mLocks &= ~NS_EVENT_STATE_VISITED;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetProperty(nsGkAtoms::lockedStyleStates, locks,
|
SetProperty(nsGkAtoms::lockedStyleStates, locks,
|
||||||
nsINode::DeleteProperty<EventStates>);
|
nsINode::DeleteProperty<StyleStateLocks>);
|
||||||
SetHasLockedStyleStates();
|
SetHasLockedStyleStates();
|
||||||
|
|
||||||
NotifyStyleStateChange(aStates);
|
NotifyStyleStateChange(aStates);
|
||||||
@ -406,18 +414,18 @@ Element::LockStyleStates(EventStates aStates)
|
|||||||
void
|
void
|
||||||
Element::UnlockStyleStates(EventStates aStates)
|
Element::UnlockStyleStates(EventStates aStates)
|
||||||
{
|
{
|
||||||
EventStates* locks = new EventStates(LockedStyleStates());
|
StyleStateLocks* locks = new StyleStateLocks(LockedStyleStates());
|
||||||
|
|
||||||
*locks &= ~aStates;
|
locks->mLocks &= ~aStates;
|
||||||
|
|
||||||
if (locks->IsEmpty()) {
|
if (locks->mLocks.IsEmpty()) {
|
||||||
DeleteProperty(nsGkAtoms::lockedStyleStates);
|
DeleteProperty(nsGkAtoms::lockedStyleStates);
|
||||||
ClearHasLockedStyleStates();
|
ClearHasLockedStyleStates();
|
||||||
delete locks;
|
delete locks;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SetProperty(nsGkAtoms::lockedStyleStates, locks,
|
SetProperty(nsGkAtoms::lockedStyleStates, locks,
|
||||||
nsINode::DeleteProperty<EventStates>);
|
nsINode::DeleteProperty<StyleStateLocks>);
|
||||||
}
|
}
|
||||||
|
|
||||||
NotifyStyleStateChange(aStates);
|
NotifyStyleStateChange(aStates);
|
||||||
@ -426,12 +434,12 @@ Element::UnlockStyleStates(EventStates aStates)
|
|||||||
void
|
void
|
||||||
Element::ClearStyleStateLocks()
|
Element::ClearStyleStateLocks()
|
||||||
{
|
{
|
||||||
EventStates locks = LockedStyleStates();
|
StyleStateLocks locks = LockedStyleStates();
|
||||||
|
|
||||||
DeleteProperty(nsGkAtoms::lockedStyleStates);
|
DeleteProperty(nsGkAtoms::lockedStyleStates);
|
||||||
ClearHasLockedStyleStates();
|
ClearHasLockedStyleStates();
|
||||||
|
|
||||||
NotifyStyleStateChange(locks);
|
NotifyStyleStateChange(locks.mLocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -244,15 +244,27 @@ public:
|
|||||||
return StyleStateFromLocks();
|
return StyleStateFromLocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StyleStateLocks is used to specify which event states should be locked,
|
||||||
|
* and whether they should be locked to on or off.
|
||||||
|
*/
|
||||||
|
struct StyleStateLocks {
|
||||||
|
// mLocks tracks which event states should be locked.
|
||||||
|
EventStates mLocks;
|
||||||
|
// mValues tracks if the locked state should be on or off.
|
||||||
|
EventStates mValues;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The style state locks applied to this element.
|
* The style state locks applied to this element.
|
||||||
*/
|
*/
|
||||||
EventStates LockedStyleStates() const;
|
StyleStateLocks LockedStyleStates() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a style state lock on this element.
|
* Add a style state lock on this element.
|
||||||
|
* aEnabled is the value to lock the given state bits to.
|
||||||
*/
|
*/
|
||||||
void LockStyleStates(EventStates aStates);
|
void LockStyleStates(EventStates aStates, bool aEnabled);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a style state lock on this element.
|
* Remove a style state lock on this element.
|
||||||
|
@ -1254,7 +1254,9 @@ inDOMUtils::GetCSSPseudoElementNames(uint32_t* aLength, char16_t*** aNames)
|
|||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
|
inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
|
||||||
const nsAString &aPseudoClass)
|
const nsAString &aPseudoClass,
|
||||||
|
bool aEnabled,
|
||||||
|
uint8_t aArgc)
|
||||||
{
|
{
|
||||||
EventStates state = GetStatesForPseudoClass(aPseudoClass);
|
EventStates state = GetStatesForPseudoClass(aPseudoClass);
|
||||||
if (state.IsEmpty()) {
|
if (state.IsEmpty()) {
|
||||||
@ -1264,7 +1266,7 @@ inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
|
|||||||
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
||||||
NS_ENSURE_ARG_POINTER(element);
|
NS_ENSURE_ARG_POINTER(element);
|
||||||
|
|
||||||
element->LockStyleStates(state);
|
element->LockStyleStates(state, aArgc > 0 ? aEnabled : true);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -1300,7 +1302,7 @@ inDOMUtils::HasPseudoClassLock(nsIDOMElement *aElement,
|
|||||||
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
||||||
NS_ENSURE_ARG_POINTER(element);
|
NS_ENSURE_ARG_POINTER(element);
|
||||||
|
|
||||||
EventStates locks = element->LockedStyleStates();
|
EventStates locks = element->LockedStyleStates().mLocks;
|
||||||
|
|
||||||
*_retval = locks.HasAllStates(state);
|
*_retval = locks.HasAllStates(state);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -185,8 +185,11 @@ interface inIDOMUtils : nsISupports
|
|||||||
|
|
||||||
// pseudo-class style locking methods. aPseudoClass must be a valid pseudo-class
|
// pseudo-class style locking methods. aPseudoClass must be a valid pseudo-class
|
||||||
// selector string, e.g. ":hover". ":any-link" and non-event-state
|
// selector string, e.g. ":hover". ":any-link" and non-event-state
|
||||||
// pseudo-classes are ignored.
|
// pseudo-classes are ignored. aEnabled sets whether the psuedo-class
|
||||||
void addPseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
|
// should be locked to on or off.
|
||||||
|
[optional_argc] void addPseudoClassLock(in nsIDOMElement aElement,
|
||||||
|
in DOMString aPseudoClass,
|
||||||
|
[optional] in boolean aEnabled);
|
||||||
void removePseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
|
void removePseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
|
||||||
bool hasPseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
|
bool hasPseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
|
||||||
void clearPseudoClassLocks(in nsIDOMElement aElement);
|
void clearPseudoClassLocks(in nsIDOMElement aElement);
|
||||||
|
Loading…
Reference in New Issue
Block a user