mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1034110 - Provide a way to observe mutations for ::before/::after pseudo elements;r=smaug
Adds a new chrome-only MutationObserverInit option called nativeAnonymousChildList that will cause a mutation to fire when a native anonymous root is bound or unbound
This commit is contained in:
parent
eb04a02f3c
commit
2d8c27349f
@ -738,6 +738,13 @@ DocAccessible::AttributeWillChange(nsIDocument* aDocument,
|
||||
mStateBitWasOn = accessible->Unavailable();
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessible::NativeAnonymousChildListChange(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
bool aIsRemove)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessible::AttributeChanged(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
|
@ -332,6 +332,13 @@ nsSHEntryShared::AttributeWillChange(nsIDocument* aDocument,
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::NativeAnonymousChildListChange(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
bool aIsRemove)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntryShared::AttributeChanged(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
|
@ -1631,6 +1631,9 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
}
|
||||
|
||||
nsNodeUtils::ParentChainChanged(this);
|
||||
if (!hadParent && IsRootOfNativeAnonymousSubtree()) {
|
||||
nsNodeUtils::NativeAnonymousChildListChange(this, false);
|
||||
}
|
||||
|
||||
if (HasID()) {
|
||||
AddToIdTable(DoGetID());
|
||||
@ -1745,6 +1748,10 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
}
|
||||
}
|
||||
|
||||
if (this->IsRootOfNativeAnonymousSubtree()) {
|
||||
nsNodeUtils::NativeAnonymousChildListChange(this, true);
|
||||
}
|
||||
|
||||
if (GetParent()) {
|
||||
nsRefPtr<nsINode> p;
|
||||
p.swap(mParent);
|
||||
|
@ -114,6 +114,38 @@ nsMutationReceiver::Disconnect(bool aRemoveFromObserver)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsMutationReceiver::NativeAnonymousChildListChange(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
bool aIsRemove) {
|
||||
if (!NativeAnonymousChildList()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsINode* parent = aContent->GetParentNode();
|
||||
if (!parent ||
|
||||
(!Subtree() && Target() != parent) ||
|
||||
(Subtree() && RegisterTarget()->SubtreeRoot() != parent->SubtreeRoot())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsDOMMutationRecord* m =
|
||||
Observer()->CurrentRecord(nsGkAtoms::nativeAnonymousChildList);
|
||||
|
||||
if (m->mTarget) {
|
||||
return;
|
||||
}
|
||||
m->mTarget = parent;
|
||||
|
||||
if (aIsRemove) {
|
||||
m->mRemovedNodes = new nsSimpleContentList(parent);
|
||||
m->mRemovedNodes->AppendElement(aContent);
|
||||
} else {
|
||||
m->mAddedNodes = new nsSimpleContentList(parent);
|
||||
m->mAddedNodes->AppendElement(aContent);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsMutationReceiver::AttributeWillChange(nsIDocument* aDocument,
|
||||
mozilla::dom::Element* aElement,
|
||||
@ -586,6 +618,8 @@ nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||
bool attributeOldValue =
|
||||
aOptions.mAttributeOldValue.WasPassed() &&
|
||||
aOptions.mAttributeOldValue.Value();
|
||||
bool nativeAnonymousChildList = aOptions.mNativeAnonymousChildList &&
|
||||
nsContentUtils::ThreadsafeIsCallerChrome();
|
||||
bool characterDataOldValue =
|
||||
aOptions.mCharacterDataOldValue.WasPassed() &&
|
||||
aOptions.mCharacterDataOldValue.Value();
|
||||
@ -605,7 +639,8 @@ nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||
characterData = true;
|
||||
}
|
||||
|
||||
if (!(childList || attributes || characterData || animations)) {
|
||||
if (!(childList || attributes || characterData || animations ||
|
||||
nativeAnonymousChildList)) {
|
||||
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
|
||||
return;
|
||||
}
|
||||
@ -655,6 +690,7 @@ nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||
r->SetSubtree(subtree);
|
||||
r->SetAttributeOldValue(attributeOldValue);
|
||||
r->SetCharacterDataOldValue(characterDataOldValue);
|
||||
r->SetNativeAnonymousChildList(nativeAnonymousChildList);
|
||||
r->SetAttributeFilter(filters);
|
||||
r->SetAllAttributes(allAttrs);
|
||||
r->SetAnimations(animations);
|
||||
@ -715,6 +751,7 @@ nsDOMMutationObserver::GetObservingInfo(
|
||||
info.mSubtree = mr->Subtree();
|
||||
info.mAttributeOldValue.Construct(mr->AttributeOldValue());
|
||||
info.mCharacterDataOldValue.Construct(mr->CharacterDataOldValue());
|
||||
info.mNativeAnonymousChildList = mr->NativeAnonymousChildList();
|
||||
info.mAnimations.Construct(mr->Animations());
|
||||
nsCOMArray<nsIAtom>& filters = mr->AttributeFilter();
|
||||
if (filters.Count()) {
|
||||
|
@ -172,6 +172,16 @@ public:
|
||||
mCharacterDataOldValue = aOldValue;
|
||||
}
|
||||
|
||||
bool NativeAnonymousChildList()
|
||||
{
|
||||
return mParent ? mParent->NativeAnonymousChildList() : mNativeAnonymousChildList;
|
||||
}
|
||||
void SetNativeAnonymousChildList(bool aOldValue)
|
||||
{
|
||||
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
||||
mNativeAnonymousChildList = aOldValue;
|
||||
}
|
||||
|
||||
bool Attributes() { return mParent ? mParent->Attributes() : mAttributes; }
|
||||
void SetAttributes(bool aAttributes)
|
||||
{
|
||||
@ -298,6 +308,7 @@ private:
|
||||
bool mChildList;
|
||||
bool mCharacterData;
|
||||
bool mCharacterDataOldValue;
|
||||
bool mNativeAnonymousChildList;
|
||||
bool mAttributes;
|
||||
bool mAllAttributes;
|
||||
bool mAttributeOldValue;
|
||||
@ -362,6 +373,7 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
|
||||
NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
|
@ -514,6 +514,8 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
}
|
||||
}
|
||||
|
||||
bool hadParent = !!GetParentNode();
|
||||
|
||||
// Set parent
|
||||
if (aParent) {
|
||||
if (!GetParent()) {
|
||||
@ -548,6 +550,9 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
}
|
||||
|
||||
nsNodeUtils::ParentChainChanged(this);
|
||||
if (!hadParent && IsRootOfNativeAnonymousSubtree()) {
|
||||
nsNodeUtils::NativeAnonymousChildListChange(this, false);
|
||||
}
|
||||
|
||||
UpdateEditableState(false);
|
||||
|
||||
@ -570,6 +575,9 @@ nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetComposedDoc();
|
||||
|
||||
if (aNullParent) {
|
||||
if (this->IsRootOfNativeAnonymousSubtree()) {
|
||||
nsNodeUtils::NativeAnonymousChildListChange(this, true);
|
||||
}
|
||||
if (GetParent()) {
|
||||
NS_RELEASE(mParent);
|
||||
} else {
|
||||
|
@ -633,6 +633,7 @@ GK_ATOM(_namespace, "namespace")
|
||||
GK_ATOM(namespaceAlias, "namespace-alias")
|
||||
GK_ATOM(namespaceUri, "namespace-uri")
|
||||
GK_ATOM(NaN, "NaN")
|
||||
GK_ATOM(nativeAnonymousChildList, "nativeAnonymousChildList")
|
||||
GK_ATOM(nav, "nav")
|
||||
GK_ATOM(negate, "negate")
|
||||
GK_ATOM(never, "never")
|
||||
|
@ -22,8 +22,8 @@ class Element;
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_IMUTATION_OBSERVER_IID \
|
||||
{ 0xdd74f0cc, 0x2849, 0x4d05, \
|
||||
{ 0x9c, 0xe3, 0xb0, 0x95, 0x3e, 0xc2, 0xfd, 0x44 } }
|
||||
{ 0x6d674c17, 0x0fbc, 0x4633, \
|
||||
{ 0x8f, 0x46, 0x73, 0x4e, 0x87, 0xeb, 0xf0, 0xc7 } }
|
||||
|
||||
/**
|
||||
* Information details about a characterdata change. Basically, we
|
||||
@ -200,6 +200,18 @@ public:
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue) = 0;
|
||||
|
||||
/**
|
||||
* Notification that the root of a native anonymous has been added
|
||||
* or removed.
|
||||
*
|
||||
* @param aDocument Owner doc of aContent
|
||||
* @param aContent Anonymous node that's been added or removed
|
||||
* @param aIsRemove True if it's a removal, false if an addition
|
||||
*/
|
||||
virtual void NativeAnonymousChildListChange(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
bool aIsRemove) {}
|
||||
|
||||
/**
|
||||
* Notification that an attribute of an element has been
|
||||
* set to the value it already had.
|
||||
@ -346,6 +358,11 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver, NS_IMUTATION_OBSERVER_IID)
|
||||
int32_t aModType, \
|
||||
const nsAttrValue* aNewValue) override;
|
||||
|
||||
#define NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE \
|
||||
virtual void NativeAnonymousChildListChange(nsIDocument* aDocument, \
|
||||
nsIContent* aContent, \
|
||||
bool aIsRemove) override;
|
||||
|
||||
#define NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED \
|
||||
virtual void AttributeChanged(nsIDocument* aDocument, \
|
||||
mozilla::dom::Element* aElement, \
|
||||
@ -383,6 +400,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver, NS_IMUTATION_OBSERVER_IID)
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE \
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED \
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE \
|
||||
NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE \
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED \
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED \
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED \
|
||||
@ -419,6 +437,12 @@ _class::AttributeWillChange(nsIDocument* aDocument, \
|
||||
{ \
|
||||
} \
|
||||
void \
|
||||
_class::NativeAnonymousChildListChange(nsIDocument* aDocument, \
|
||||
nsIContent* aContent, \
|
||||
bool aIsRemove) \
|
||||
{ \
|
||||
} \
|
||||
void \
|
||||
_class::AttributeChanged(nsIDocument* aDocument, \
|
||||
mozilla::dom::Element* aElement, \
|
||||
int32_t aNameSpaceID, \
|
||||
|
@ -167,6 +167,15 @@ nsNodeUtils::ContentAppended(nsIContent* aContainer,
|
||||
aNewIndexInContainer));
|
||||
}
|
||||
|
||||
void
|
||||
nsNodeUtils::NativeAnonymousChildListChange(nsIContent* aContent,
|
||||
bool aIsRemove)
|
||||
{
|
||||
nsIDocument* doc = aContent->OwnerDoc();
|
||||
IMPL_MUTATION_NOTIFICATION(NativeAnonymousChildListChange, aContent,
|
||||
(doc, aContent, aIsRemove));
|
||||
}
|
||||
|
||||
void
|
||||
nsNodeUtils::ContentInserted(nsINode* aContainer,
|
||||
nsIContent* aChild,
|
||||
|
@ -96,6 +96,15 @@ public:
|
||||
nsIContent* aFirstNewContent,
|
||||
int32_t aNewIndexInContainer);
|
||||
|
||||
/**
|
||||
* Send NativeAnonymousChildList notifications to nsIMutationObservers
|
||||
* @param aContent Anonymous node that's been added or removed
|
||||
* @param aIsRemove True if it's a removal, false if an addition
|
||||
* @see nsIMutationObserver::NativeAnonymousChildListChange
|
||||
*/
|
||||
static void NativeAnonymousChildListChange(nsIContent* aContent,
|
||||
bool aIsRemove);
|
||||
|
||||
/**
|
||||
* Send ContentInserted notifications to nsIMutationObservers
|
||||
* @param aContainer Node into which new child was inserted
|
||||
|
@ -65,6 +65,7 @@ skip-if = buildapp == 'mulet'
|
||||
[test_cpows.xul]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_document_register.xul]
|
||||
[test_mutationobserver_anonymous.html]
|
||||
[test_registerElement_content.xul]
|
||||
[test_registerElement_ep.xul]
|
||||
[test_domparsing.xul]
|
||||
|
247
dom/base/test/chrome/test_mutationobserver_anonymous.html
Normal file
247
dom/base/test/chrome/test_mutationobserver_anonymous.html
Normal file
@ -0,0 +1,247 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1034110
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1034110</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1034110">Mozilla Bug 1034110</a>
|
||||
<style type="text/css">
|
||||
#pseudo.before::before { content: "before"; }
|
||||
#pseudo.after::after { content: "after"; }
|
||||
</style>
|
||||
<div id="pseudo"></div>
|
||||
<video id="video"></video>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
/** Test for Bug 1034110 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
const {Cc, Ci, Cu} = SpecialPowers;
|
||||
|
||||
function getWalker(node) {
|
||||
let walker = Cc["@mozilla.org/inspector/deep-tree-walker;1"].createInstance(Ci.inIDeepTreeWalker);
|
||||
walker.showAnonymousContent = true;
|
||||
walker.init(node.ownerDocument, Ci.nsIDOMNodeFilter.SHOW_ALL);
|
||||
walker.currentNode = node;
|
||||
return walker;
|
||||
}
|
||||
|
||||
function getFirstChild(parent) {
|
||||
return SpecialPowers.unwrap(getWalker(parent).firstChild());
|
||||
}
|
||||
|
||||
function getLastChild(parent) {
|
||||
return SpecialPowers.unwrap(getWalker(parent).lastChild());
|
||||
}
|
||||
|
||||
function assertSamePseudoElement(which, node1, node2) {
|
||||
is(node1.nodeName, "_moz_generated_content_" + which,
|
||||
"Correct pseudo element type");
|
||||
is(node1, node2,
|
||||
"Referencing the same ::after element");
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
testOneAdded();
|
||||
};
|
||||
|
||||
function testOneAdded() {
|
||||
let parent = document.getElementById("pseudo");
|
||||
var m = new MutationObserver(function(records, observer) {
|
||||
is(records.length, 1, "Correct number of records");
|
||||
is(records[0].type, "nativeAnonymousChildList", "Correct record type");
|
||||
is(records[0].target, parent, "Correct target");
|
||||
|
||||
is(records[0].addedNodes.length, 1, "Should have got addedNodes");
|
||||
assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
|
||||
is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
|
||||
|
||||
observer.disconnect();
|
||||
testAddedAndRemoved();
|
||||
});
|
||||
|
||||
m.observe(parent, { nativeAnonymousChildList: true});
|
||||
parent.className = "before";
|
||||
}
|
||||
|
||||
function testAddedAndRemoved() {
|
||||
let parent = document.getElementById("pseudo");
|
||||
let originalBeforeElement = getFirstChild(parent);
|
||||
var m = new MutationObserver(function(records, observer) {
|
||||
is(records.length, 2, "Correct number of records");
|
||||
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
|
||||
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
|
||||
is(records[0].target, parent, "Correct target (1)");
|
||||
is(records[1].target, parent, "Correct target (2)");
|
||||
|
||||
// Two records are sent - one for removed and one for added.
|
||||
is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
|
||||
is(records[0].removedNodes.length, 1, "Should have got removedNodes");
|
||||
assertSamePseudoElement("before", records[0].removedNodes[0], originalBeforeElement);
|
||||
|
||||
is(records[1].addedNodes.length, 1, "Should have got addedNodes");
|
||||
assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
|
||||
is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
|
||||
|
||||
observer.disconnect();
|
||||
testRemoved();
|
||||
});
|
||||
|
||||
m.observe(parent, { nativeAnonymousChildList: true});
|
||||
parent.className = "after";
|
||||
}
|
||||
|
||||
function testRemoved() {
|
||||
let parent = document.getElementById("pseudo");
|
||||
let originalAfterElement = getLastChild(parent);
|
||||
var m = new MutationObserver(function(records, observer) {
|
||||
is(records.length, 1, "Correct number of records");
|
||||
is(records[0].type, "nativeAnonymousChildList", "Correct record type");
|
||||
is(records[0].target, parent, "Correct target");
|
||||
|
||||
is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
|
||||
is(records[0].removedNodes.length, 1, "Should have got removedNodes");
|
||||
assertSamePseudoElement("after", records[0].removedNodes[0], originalAfterElement);
|
||||
|
||||
observer.disconnect();
|
||||
testMultipleAdded();
|
||||
});
|
||||
|
||||
m.observe(parent, { nativeAnonymousChildList: true });
|
||||
parent.className = "";
|
||||
}
|
||||
|
||||
function testMultipleAdded() {
|
||||
let parent = document.getElementById("pseudo");
|
||||
var m = new MutationObserver(function(records, observer) {
|
||||
is(records.length, 2, "Correct number of records");
|
||||
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
|
||||
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
|
||||
is(records[0].target, parent, "Correct target (1)");
|
||||
is(records[1].target, parent, "Correct target (2)");
|
||||
|
||||
is(records[0].addedNodes.length, 1, "Should have got addedNodes");
|
||||
assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
|
||||
is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
|
||||
|
||||
is(records[1].addedNodes.length, 1, "Should have got addedNodes");
|
||||
assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
|
||||
is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
|
||||
|
||||
observer.disconnect();
|
||||
testRemovedDueToDisplay();
|
||||
});
|
||||
|
||||
m.observe(parent, { nativeAnonymousChildList: true });
|
||||
parent.className = "before after";
|
||||
}
|
||||
|
||||
function testRemovedDueToDisplay() {
|
||||
let parent = document.getElementById("pseudo");
|
||||
let originalBeforeElement = getFirstChild(parent);
|
||||
let originalAfterElement = getLastChild(parent);
|
||||
var m = new MutationObserver(function(records, observer) {
|
||||
is(records.length, 2, "Correct number of records");
|
||||
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
|
||||
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
|
||||
is(records[0].target, parent, "Correct target (1)");
|
||||
is(records[1].target, parent, "Correct target (2)");
|
||||
|
||||
is(records[0].addedNodes.length, 0, "Shouldn't have got addedNodes");
|
||||
is(records[0].removedNodes.length, 1, "Should have got removedNodes");
|
||||
assertSamePseudoElement("before", records[0].removedNodes[0], originalBeforeElement);
|
||||
|
||||
is(records[1].addedNodes.length, 0, "Shouldn't have got addedNodes");
|
||||
is(records[1].removedNodes.length, 1, "Should have got removedNodes");
|
||||
assertSamePseudoElement("after", records[1].removedNodes[0], originalAfterElement);
|
||||
|
||||
observer.disconnect();
|
||||
testAddedDueToDisplay();
|
||||
});
|
||||
|
||||
m.observe(parent, { nativeAnonymousChildList: true });
|
||||
parent.style.display = "none";
|
||||
}
|
||||
|
||||
function testAddedDueToDisplay() {
|
||||
let parent = document.getElementById("pseudo");
|
||||
var m = new MutationObserver(function(records, observer) {
|
||||
is(records.length, 2, "Correct number of records");
|
||||
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
|
||||
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
|
||||
is(records[0].target, parent, "Correct target (1)");
|
||||
is(records[1].target, parent, "Correct target (2)");
|
||||
|
||||
is(records[0].addedNodes.length, 1, "Should have got addedNodes");
|
||||
assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
|
||||
is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
|
||||
|
||||
is(records[1].addedNodes.length, 1, "Should have got addedNodes");
|
||||
assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
|
||||
is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
|
||||
|
||||
observer.disconnect();
|
||||
testDifferentTargetNoSubtree();
|
||||
});
|
||||
|
||||
m.observe(parent, { nativeAnonymousChildList: true });
|
||||
parent.style.display = "block";
|
||||
}
|
||||
|
||||
function testDifferentTargetNoSubtree() {
|
||||
let parent = document.getElementById("pseudo");
|
||||
var m = new MutationObserver(function(records, observer) {
|
||||
ok(false,
|
||||
"No mutation should fire when observing on a parent without subtree option.");
|
||||
});
|
||||
m.observe(document, { nativeAnonymousChildList: true });
|
||||
parent.style.display = "none";
|
||||
|
||||
setTimeout(() => {
|
||||
ok(!getFirstChild(parent), "Pseudo element has been removed, but no mutation");
|
||||
ok(!getLastChild(parent), "Pseudo element has been removed, but no mutation");
|
||||
testSubtree();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function testSubtree() {
|
||||
let parent = document.getElementById("pseudo");
|
||||
var m = new MutationObserver(function(records, observer) {
|
||||
is(records.length, 2, "Correct number of records");
|
||||
is(records[0].type, "nativeAnonymousChildList", "Correct record type (1)");
|
||||
is(records[1].type, "nativeAnonymousChildList", "Correct record type (2)");
|
||||
is(records[0].target, parent, "Correct target (1)");
|
||||
is(records[1].target, parent, "Correct target (2)");
|
||||
|
||||
is(records[0].addedNodes.length, 1, "Should have got addedNodes");
|
||||
assertSamePseudoElement("before", records[0].addedNodes[0], getFirstChild(parent));
|
||||
is(records[0].removedNodes.length, 0, "Shouldn't have got removedNodes");
|
||||
|
||||
is(records[1].addedNodes.length, 1, "Should have got addedNodes");
|
||||
assertSamePseudoElement("after", records[1].addedNodes[0], getLastChild(parent));
|
||||
is(records[1].removedNodes.length, 0, "Shouldn't have got removedNodes");
|
||||
|
||||
observer.disconnect();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
m.observe(document, { nativeAnonymousChildList: true, subtree: true });
|
||||
parent.style.display = "block";
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -909,6 +909,19 @@ function testAttributeRecordMerging4() {
|
||||
m.disconnect();
|
||||
div.innerHTML = "";
|
||||
div.removeAttribute("foo");
|
||||
then(testChromeOnly);
|
||||
}
|
||||
|
||||
function testChromeOnly() {
|
||||
// Content can't access nativeAnonymousChildList
|
||||
try {
|
||||
var mo = new M(function(records, observer) { });
|
||||
mo.observe(div, { nativeAnonymousChildList: true });
|
||||
ok(false, "Should have thrown when trying to observe with chrome-only init");
|
||||
} catch (e) {
|
||||
ok(true, "Throws when trying to observe with chrome-only init");
|
||||
}
|
||||
|
||||
then();
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,8 @@ dictionary MutationObserverInit {
|
||||
boolean attributeOldValue;
|
||||
boolean characterDataOldValue;
|
||||
// [ChromeOnly]
|
||||
boolean nativeAnonymousChildList = false;
|
||||
// [ChromeOnly]
|
||||
boolean animations;
|
||||
sequence<DOMString> attributeFilter;
|
||||
};
|
||||
|
@ -194,6 +194,13 @@ nsFormFillController::AttributeWillChange(nsIDocument* aDocument,
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFormFillController::NativeAnonymousChildListChange(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
bool aIsRemove)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsFormFillController::ParentChainChanged(nsIContent* aContent)
|
||||
{
|
||||
|
@ -106,6 +106,11 @@ void nsMenuGroupOwnerX::AttributeWillChange(nsIDocument* aDocument,
|
||||
{
|
||||
}
|
||||
|
||||
void nsMenuGroupOwnerX::NativeAnonymousChildListChange(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
bool aIsRemove)
|
||||
{
|
||||
}
|
||||
|
||||
void nsMenuGroupOwnerX::AttributeChanged(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
|
Loading…
Reference in New Issue
Block a user