mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +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:
|
||||
* `parents`: True if the pseudo-class should be added
|
||||
* 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
|
||||
* 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) {
|
||||
return;
|
||||
@ -1782,7 +1786,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
||||
let cur;
|
||||
while ((cur = walker.parentNode())) {
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
DOMUtils.addPseudoClassLock(node.rawNode, pseudo);
|
||||
DOMUtils.addPseudoClassLock(node.rawNode, pseudo, enabled);
|
||||
this._activePseudoClassLocks.add(node);
|
||||
this._queuePseudoClassMutation(node);
|
||||
return true;
|
||||
|
@ -1,3 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
|
@ -60,16 +60,21 @@ function checkChange(change, expectation) {
|
||||
|
||||
is(target.pseudoClassLocks.length, expectation.pseudos.length,
|
||||
"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(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) {
|
||||
if (!expectation.pseudos.some(expected => pseudo === expected)) {
|
||||
ok(!target.hasPseudoClassLock(pseudo), "Don't expect lock: " + 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.
|
||||
return promiseOnce(gWalker, "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");
|
||||
checkChange(mutations[0], {
|
||||
id: "b",
|
||||
@ -149,6 +154,18 @@ addTest(function testPseudoClassLock() {
|
||||
pseudos: []
|
||||
}];
|
||||
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(() => {
|
||||
// Now shut down the walker and make sure that clears up the remaining lock.
|
||||
return gWalker.release();
|
||||
|
@ -234,7 +234,8 @@ const walkerSpec = generateActorSpec({
|
||||
request: {
|
||||
node: Arg(0, "domnode"),
|
||||
pseudoClass: Arg(1),
|
||||
parents: Option(2)
|
||||
parents: Option(2),
|
||||
enabled: Option(2, "boolean"),
|
||||
},
|
||||
response: {}
|
||||
},
|
||||
|
@ -346,27 +346,30 @@ Element::Blur(mozilla::ErrorResult& aError)
|
||||
EventStates
|
||||
Element::StyleStateFromLocks() const
|
||||
{
|
||||
EventStates locks = LockedStyleStates();
|
||||
EventStates state = mState | locks;
|
||||
StyleStateLocks locksAndValues = LockedStyleStates();
|
||||
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;
|
||||
}
|
||||
if (locks.HasState(NS_EVENT_STATE_UNVISITED)) {
|
||||
if (state.HasState(NS_EVENT_STATE_UNVISITED)) {
|
||||
return state & ~NS_EVENT_STATE_VISITED;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
EventStates
|
||||
Element::StyleStateLocks
|
||||
Element::LockedStyleStates() const
|
||||
{
|
||||
EventStates* locks =
|
||||
static_cast<EventStates*>(GetProperty(nsGkAtoms::lockedStyleStates));
|
||||
StyleStateLocks* locks =
|
||||
static_cast<StyleStateLocks*>(GetProperty(nsGkAtoms::lockedStyleStates));
|
||||
if (locks) {
|
||||
return *locks;
|
||||
}
|
||||
return EventStates();
|
||||
return StyleStateLocks();
|
||||
}
|
||||
|
||||
void
|
||||
@ -383,21 +386,26 @@ Element::NotifyStyleStateChange(EventStates aStates)
|
||||
}
|
||||
|
||||
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)) {
|
||||
*locks &= ~NS_EVENT_STATE_UNVISITED;
|
||||
locks->mLocks &= ~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,
|
||||
nsINode::DeleteProperty<EventStates>);
|
||||
nsINode::DeleteProperty<StyleStateLocks>);
|
||||
SetHasLockedStyleStates();
|
||||
|
||||
NotifyStyleStateChange(aStates);
|
||||
@ -406,18 +414,18 @@ Element::LockStyleStates(EventStates aStates)
|
||||
void
|
||||
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);
|
||||
ClearHasLockedStyleStates();
|
||||
delete locks;
|
||||
}
|
||||
else {
|
||||
SetProperty(nsGkAtoms::lockedStyleStates, locks,
|
||||
nsINode::DeleteProperty<EventStates>);
|
||||
nsINode::DeleteProperty<StyleStateLocks>);
|
||||
}
|
||||
|
||||
NotifyStyleStateChange(aStates);
|
||||
@ -426,12 +434,12 @@ Element::UnlockStyleStates(EventStates aStates)
|
||||
void
|
||||
Element::ClearStyleStateLocks()
|
||||
{
|
||||
EventStates locks = LockedStyleStates();
|
||||
StyleStateLocks locks = LockedStyleStates();
|
||||
|
||||
DeleteProperty(nsGkAtoms::lockedStyleStates);
|
||||
ClearHasLockedStyleStates();
|
||||
|
||||
NotifyStyleStateChange(locks);
|
||||
NotifyStyleStateChange(locks.mLocks);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -244,15 +244,27 @@ public:
|
||||
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.
|
||||
*/
|
||||
EventStates LockedStyleStates() const;
|
||||
StyleStateLocks LockedStyleStates() const;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -1254,7 +1254,9 @@ inDOMUtils::GetCSSPseudoElementNames(uint32_t* aLength, char16_t*** aNames)
|
||||
|
||||
NS_IMETHODIMP
|
||||
inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
|
||||
const nsAString &aPseudoClass)
|
||||
const nsAString &aPseudoClass,
|
||||
bool aEnabled,
|
||||
uint8_t aArgc)
|
||||
{
|
||||
EventStates state = GetStatesForPseudoClass(aPseudoClass);
|
||||
if (state.IsEmpty()) {
|
||||
@ -1264,7 +1266,7 @@ inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
|
||||
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
||||
NS_ENSURE_ARG_POINTER(element);
|
||||
|
||||
element->LockStyleStates(state);
|
||||
element->LockStyleStates(state, aArgc > 0 ? aEnabled : true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1300,7 +1302,7 @@ inDOMUtils::HasPseudoClassLock(nsIDOMElement *aElement,
|
||||
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
||||
NS_ENSURE_ARG_POINTER(element);
|
||||
|
||||
EventStates locks = element->LockedStyleStates();
|
||||
EventStates locks = element->LockedStyleStates().mLocks;
|
||||
|
||||
*_retval = locks.HasAllStates(state);
|
||||
return NS_OK;
|
||||
|
@ -185,8 +185,11 @@ interface inIDOMUtils : nsISupports
|
||||
|
||||
// pseudo-class style locking methods. aPseudoClass must be a valid pseudo-class
|
||||
// selector string, e.g. ":hover". ":any-link" and non-event-state
|
||||
// pseudo-classes are ignored.
|
||||
void addPseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
|
||||
// pseudo-classes are ignored. aEnabled sets whether the psuedo-class
|
||||
// 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);
|
||||
bool hasPseudoClassLock(in nsIDOMElement aElement, in DOMString aPseudoClass);
|
||||
void clearPseudoClassLocks(in nsIDOMElement aElement);
|
||||
|
Loading…
Reference in New Issue
Block a user