public void MutationObserverAttrWithOldvalue() { var document = Html(""); var div = document.CreateElement("div"); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, attributes: true, attributeOldValue: true); div.SetAttribute("a", "A"); div.SetAttribute("a", "B"); var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a", AttributeNamespace = null, PreviousValue = null }); AssertRecord(records[1], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a", AttributeNamespace = null, PreviousValue = "A" }); }
public SpecificChildListChangedObserver() { _observer = new MutationObserver((changes, _) => { Logger.Debug(GetType(), "[SpecificChildListChangedObserver] dom nodes mutation detected - got {0} items", changes.Length); var triggered = 0; changes.ForEach(change => change.AddedNodes .Where(x => x.NodeType == NodeType.Element) .Select(x => x.AsElementOrNull()) .ForEach(added => triggered += added.TraverseAll(el => { if (!_onAddedListeners.ContainsKey(el)) { return(false); } _onAddedListeners[el].ForEach(x => x()); return(true); })) ); Logger.Debug(GetType(), "triggered {0} listeners", triggered); }); _observer.Observe(Document.Body, new MutationObserverInit { Subtree = true, ChildList = true }); }
public void MutationObserverCharacterdata() { var document = Html("", true); var text = document.CreateTextNode("abc"); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(text, characterData: true); text.TextContent = "def"; text.TextContent = "ghi"; var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "characterData", Target = text }); AssertRecord(records[1], new TestMutationRecord { Type = "characterData", Target = text }); }
public void MutationObserverCharacterdataCallback() { var document = Html(""); var div = document.CreateElement("div"); var child = div.AppendChild(document.CreateTextNode("text")); var i = 0; var observer = new MutationObserver((records, obs) => { Assert.LessOrEqual(++i, 2); Assert.AreEqual(1, records.Count()); AssertRecord(records[0], new TestMutationRecord { Type = "characterData", Target = child }); // The transient observers are removed before the callback is called. child.TextContent += " again"; records = obs.Flush().ToArray(); Assert.AreEqual(0, records.Count()); }); observer.Connect(div, characterData: true, subtree: true); div.RemoveChild(child); child.TextContent = "changed"; observer.Trigger(); }
public void MutationObserverCharacterdataWithOldValue() { var document = Html(""); var testDiv = document.Body.AppendChild(document.CreateElement("div")); var text = testDiv.AppendChild(document.CreateTextNode("abc")); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(text, characterData: true, characterDataOldValue: true); text.TextContent = "def"; text.TextContent = "ghi"; var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "characterData", Target = text, PreviousValue = "abc" }); AssertRecord(records[1], new TestMutationRecord { Type = "characterData", Target = text, PreviousValue = "def" }); }
public void MutationObserverAttrChangeSubtree() { var document = Html(""); var div = document.CreateElement("div"); var child = document.CreateElement("div"); div.AppendChild(child); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, attributes: true, subtree: true); child.SetAttribute("a", "A"); child.SetAttribute("a", "B"); var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = child, AttributeName = "a" }); AssertRecord(records[1], new TestMutationRecord { Type = "attributes", Target = child, AttributeName = "a" }); }
public void MutationObserverBothDirectAndSubtree() { var document = Html(""); var div = document.CreateElement("div"); var child = div.AppendChild(document.CreateElement("div")); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, childList: true, subtree: true); observer.Connect(child, childList: true); var a = document.CreateTextNode("a"); var b = document.CreateTextNode("b"); child.AppendChild(a); div.AppendChild(b); var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "childList", Target = child, Added = ToNodeList(a) }); AssertRecord(records[1], new TestMutationRecord { Type = "childList", Target = div, Added = ToNodeList(b), PreviousSibling = child }); }
public void MutationObserverCharacterdataChangeInSubtree() { var document = Html(""); var div = document.CreateElement("div"); var text = div.AppendChild(document.CreateTextNode("abc")); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, characterData: true, subtree: true); text.TextContent = "def"; text.TextContent = "ghi"; var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "characterData", Target = text }); AssertRecord(records[1], new TestMutationRecord { Type = "characterData", Target = text }); }
public void MutationObserverAppendMultipleAtOnceInTheMiddle() { var document = Html(""); var testDiv = document.Body.AppendChild(document.CreateElement("div")); var div = document.CreateElement("div"); testDiv.AppendChild(div); var a = div.AppendChild(document.CreateTextNode("a")); var b = div.AppendChild(document.CreateTextNode("b")); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, childList: true); var df = document.CreateDocumentFragment(); var c = df.AppendChild(document.CreateTextNode("c")); var d = df.AppendChild(document.CreateTextNode("d")); div.InsertBefore(df, b); var records = observer.Flush().ToArray(); var merged = MergeRecords(records); AssertArrayEqual(merged.Item1, ToNodeList(c, d)); AssertArrayEqual(merged.Item2, ToNodeList()); AssertAll(records, new TestMutationRecord { Type = "childList", Target = div }); }
public void MutationObserverOneObserverTwoAttributeChanges() { var document = Html(""); var div = document.CreateElement("div"); var observer = new MutationObserver((records, obs) => { Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a", AttributeNamespace = null }); AssertRecord(records[1], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a", AttributeNamespace = null }); }); observer.Connect(div, attributes: true); div.SetAttribute("a", "A"); div.SetAttribute("a", "B"); }
public void MutationObserverChildListCharacterdata() { var document = Html(""); var div = document.CreateElement("div"); var child = div.AppendChild(document.CreateTextNode("text")); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, characterData: true, subtree: true); div.RemoveChild(child); child.TextContent = "changed"; var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 1); AssertRecord(records[0], new TestMutationRecord { Type = "characterData", Target = child }); child.TextContent += " again"; records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 1); AssertRecord(records[0], new TestMutationRecord { Type = "characterData", Target = child }); }
public void MutationObserverAttrCallback() { var document = Html(""); var testDiv = document.Body.AppendChild(document.CreateElement("div")); var div = testDiv.AppendChild(document.CreateElement("div")); var child = document.CreateElement("div"); div.AppendChild(child); var i = 0; var observer = new MutationObserver((records, obs) => { Assert.LessOrEqual(++i, 2); Assert.AreEqual(1, records.Count()); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = child, AttributeName = "a", AttributeNamespace = null }); // The transient observers are removed before the callback is called. child.SetAttribute("b", "B"); records = obs.Flush().ToArray(); Assert.AreEqual(0, records.Count()); }); observer.Connect(div, attributes: true, subtree: true); div.RemoveChild(child); child.SetAttribute("a", "A"); observer.Trigger(); }
public void MutationObserverAttrAndCharacterdata() { var document = Html(""); var div = document.CreateElement("div"); var text = div.AppendChild(document.CreateTextNode("text")); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, attributes: true, subtree: true, characterData: true); div.SetAttribute("a", "A"); div.FirstChild.TextContent = "changed"; var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a", AttributeNamespace = null }); AssertRecord(records[1], new TestMutationRecord { Type = "characterData", Target = div.FirstChild }); }
public void MutationObserverReplaceAllChildrenUsingInnerhtml() { var document = Html(""); var testDiv = document.Body.AppendChild(document.CreateElement("div")); var div = document.CreateElement("div"); testDiv.AppendChild(div); var a = div.AppendChild(document.CreateTextNode("a")); var b = div.AppendChild(document.CreateTextNode("b")); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, childList: true); div.InnerHtml = "<c></c><d></d>"; var c = div.FirstChild; var d = div.LastChild; var records = observer.Flush().ToArray(); var merged = MergeRecords(records); AssertArrayEqual(merged.Item1, ToNodeList(c, d)); AssertArrayEqual(merged.Item2, ToNodeList(a, b)); AssertAll(records, new TestMutationRecord { Type = "childList", Target = div }); }
public async Task MutationObserverOneObserverTwoAttributeChanges() { var document = Html("", true); var div = document.CreateElement("div"); var tcs = new TaskCompletionSource <Boolean>(); var observer = new MutationObserver((records, obs) => { Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a", AttributeNamespace = null }); AssertRecord(records[1], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a", AttributeNamespace = null }); tcs.SetResult(true); }); observer.Connect(div, attributes: true); div.SetAttribute("a", "A"); div.SetAttribute("a", "B"); await tcs.Task.ConfigureAwait(false); }
public void ConnectMutationObserverTextWithDescendentsAndExaminingOldValueTriggerManually() { var called = false; var text = "something"; var replaced = "different"; var observer = new MutationObserver((mut, obs) => { called = true; Assert.AreEqual(1, mut.Length); Assert.AreEqual(text, mut[0].PreviousValue); var tn = mut[0].Target as TextNode; Assert.IsNotNull(tn); Assert.AreEqual(text + replaced, tn.TextContent); }); var document = Html(""); observer.Connect(document.Body, characterData: true, subtree: true, characterDataOldValue: true); document.Body.TextContent = text; var textNode = document.Body.ChildNodes[0] as TextNode; textNode.Replace(text.Length, 0, replaced); observer.TriggerWith(observer.Flush().ToArray()); Assert.IsTrue(called); }
public void TestNewlyAttachedElements() { Records = null; var done = Assert.Async(); var root = HtmlHelper.FixtureElement; //setup observer var observer = new MutationObserver((changes, _) => { if (changes.Length > 0) { Records = changes; } }); observer.Observe(root, new MutationObserverInit { Subtree = true, ChildList = true }); Task task = new Task(() => { // mutate DOM // observer will be invoked asynchronously root.AppendChild(new HTMLSpanElement()); }); var task1 = task.ContinueWith(x => { Task.Delay(10); }); task1.ContinueWith(x => { try { AssertRecords(this.Records); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } observer.Disconnect(); done(); }); task.Start(); }
public void MutationObserverAttrMakeSureTransientGetsRemoved() { var document = Html(""); var testDiv = document.Body.AppendChild(document.CreateElement("div")); var div = testDiv.AppendChild(document.CreateElement("div")); var child = document.CreateElement("div"); div.AppendChild(child); var i = 0; var observer = new MutationObserver((records, obs) => { Assert.AreNotEqual(2, ++i); Assert.AreEqual(records.Count(), 1); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = child, AttributeName = "a", AttributeNamespace = null }); }); observer.Connect(div, subtree: true, attributes: true); div.RemoveChild(child); child.SetAttribute("a", "A"); observer.Trigger(); var div2 = document.CreateElement("div"); var observer2 = new MutationObserver((records, obs) => { Assert.LessOrEqual(++i, 3); Assert.AreEqual(records.Count(), 1); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = child, AttributeName = "b", AttributeNamespace = null }); }); observer2.Connect(div2, attributes: true, subtree: true); div2.AppendChild(child); child.SetAttribute("b", "B"); observer2.Trigger(); }
public void MutationObserverMultipleObserversOnSameTarget() { var document = Html(""); var div = document.CreateElement("div"); var observer1 = new MutationObserver((obs, mut) => { }); observer1.Connect(div, attributes: true, attributeOldValue: true); var observer2 = new MutationObserver((obs, mut) => { }); observer2.Connect(div, attributes: true, attributeFilter: new [] { "b" }); div.SetAttribute("a", "A"); div.SetAttribute("a", "A2"); div.SetAttribute("b", "B"); var records = observer1.Flush().ToArray(); Assert.AreEqual(records.Count(), 3); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a" }); AssertRecord(records[1], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a", PreviousValue = "A" }); AssertRecord(records[2], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "b" }); records = observer2.Flush().ToArray(); Assert.AreEqual(1, records.Count()); AssertRecord(records[0], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "b" }); }
public void MutationObserverCharacterdataChangeInSubtreeShouldNotGenerateARecord() { var document = Html(""); var div = document.CreateElement("div"); var text = div.AppendChild(document.CreateTextNode("abc")); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, characterData: true); text.TextContent = "def"; text.TextContent = "ghi"; var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 0); }
public static void Run() { // ExStart:MutationObserver // The path to the documents directory. string dataDir = RunExamples.GetDataDir_Data(); // The MutationObserver interface provides the ability to watch for changes being made to the DOM tree. // Create an empty document using (var document = new HTMLDocument()) { // Create a WaitHandle for purpose described below var @event = new ManualResetEvent(false); // Create an observer instance var observer = new MutationObserver((mutations, mutationObserver) => { var mutation = mutations[0]; Console.WriteLine(mutation.AddedNodes[0]); @event.Set(); }); // Options for the observer (which mutations to observe) var config = new MutationObserverInit { ChildList = true, Subtree = true }; // Start observing the target node observer.Observe(document.DocumentElement, config); // An example of user modifications var p = document.CreateElement("p"); document.DocumentElement.AppendChild(p); // Since, mutations are working in the async mode you should wait a bit. We use WaitHandle for this purpose. @event.WaitOne(); // Later, you can stop observing observer.Disconnect(); } // ExEnd:MutationObserver }
public void MutationObserverDisconnectShouldStopAllEventsAndEmptyTheRecords() { var document = Html(""); var div = document.CreateElement("div"); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, attributes: true); div.SetAttribute("a", "A"); observer.Disconnect(); var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 0); div.SetAttribute("b", "B"); records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 0); }
public void MutationObserverAttrChangeInSubtreeShouldNotGenereateARecord() { var document = Html(""); var div = document.CreateElement("div"); var child = document.CreateElement("div"); div.AppendChild(child); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(div, attributes: true); child.SetAttribute("a", "A"); child.SetAttribute("a", "B"); var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 0); }
public void ConnectMutationObserverChildNodesTriggerManually() { var called = false; var observer = new MutationObserver((mut, obs) => { called = true; Assert.AreEqual(1, mut.Length); var record = mut[0]; Assert.IsNotNull(record.Added); Assert.AreEqual(1, record.Added.Length); }); var document = Html(""); observer.Connect(document.Body, childList: true); document.Body.AppendChild(document.CreateElement("span")); Assert.IsTrue(called); }
public async Task MutationObserverChildlistCallback() { var document = Html("", true); var testDiv = document.Body.AppendChild(document.CreateElement("div")); var div = testDiv.AppendChild(document.CreateElement("div")); var child = div.AppendChild(document.CreateElement("div")); var grandChild = document.CreateElement("span"); var i = 0; var tcs = new TaskCompletionSource <Boolean>(); var observer = new MutationObserver((records, obs) => { Assert.LessOrEqual(++i, 2); Assert.AreEqual(2, records.Count()); AssertRecord(records[0], new TestMutationRecord { Type = "childList", Target = div, Removed = ToNodeList(child) }); AssertRecord(records[1], new TestMutationRecord { Type = "childList", Target = child, Added = ToNodeList(grandChild) }); // The transient observers are removed before the callback is called. child.RemoveChild(grandChild); records = obs.Flush().ToArray(); Assert.AreEqual(0, records.Count()); tcs.SetResult(true); }); observer.Connect(div, childList: true, subtree: true); div.RemoveChild(child); child.AppendChild(grandChild); observer.Trigger(); await tcs.Task.ConfigureAwait(false); }
public void MutationObserverChildlist() { var document = Html(""); var testDiv = document.Body.AppendChild(document.CreateElement("div")); var div = testDiv.AppendChild(document.CreateElement("div")); var child = div.AppendChild(document.CreateElement("div")); var observer = new MutationObserver((mut, obs) => { }); observer.Connect(div, childList: true, subtree: true); div.RemoveChild(child); var grandChild = child.AppendChild(document.CreateElement("span")); var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 2); AssertRecord(records[0], new TestMutationRecord { Type = "childList", Target = div, Removed = ToNodeList(child) }); AssertRecord(records[1], new TestMutationRecord { Type = "childList", Target = child, Added = ToNodeList(grandChild) }); child.RemoveChild(grandChild); records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 1); AssertRecord(records[0], new TestMutationRecord { Type = "childList", Target = child, Removed = ToNodeList(grandChild) }); }
public void MutationObserverSubtree() { var document = Html(""); var div = document.CreateElement("div"); var child = div.AppendChild(document.CreateElement("div")); var observer = new MutationObserver((obs, mut) => { }); observer.Connect(child, childList: true); var a = document.CreateTextNode("a"); var b = document.CreateTextNode("b"); child.AppendChild(a); child.InsertBefore(b, a); child.RemoveChild(b); var records = observer.Flush().ToArray(); Assert.AreEqual(records.Count(), 3); AssertRecord(records[0], new TestMutationRecord { Type = "childList", Target = child, Added = ToNodeList(a) }); AssertRecord(records[1], new TestMutationRecord { Type = "childList", Target = child, NextSibling = a, Added = ToNodeList(b) }); AssertRecord(records[2], new TestMutationRecord { Type = "childList", Target = child, NextSibling = a, Removed = ToNodeList(b) }); }
public void MutationObserverDisconnectShouldNotAffectOtherObservers() { var document = Html(""); var div = document.CreateElement("div"); var observer1 = new MutationObserver((obs, mut) => { }); observer1.Connect(div, attributes: true); var observer2 = new MutationObserver((obs, mut) => { }); observer2.Connect(div, attributes: true); div.SetAttribute("a", "A"); observer1.Disconnect(); var records1 = observer1.Flush().ToArray(); Assert.AreEqual(records1.Count(), 0); var records2 = observer2.Flush().ToArray(); Assert.AreEqual(records2.Count(), 1); AssertRecord(records2[0], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "a" }); div.SetAttribute("b", "B"); records1 = observer1.Flush().ToArray(); Assert.AreEqual(records1.Count(), 0); records2 = observer2.Flush().ToArray(); Assert.AreEqual(records2.Count(), 1); AssertRecord(records2[0], new TestMutationRecord { Type = "attributes", Target = div, AttributeName = "b" }); }
public void ConnectMutationObserverMultipleAttributesDescendentTriggerManually() { var called1 = false; var called2 = false; var called3 = false; var attrName = "something"; var attrValue = "test"; var document = Html(""); var observer1 = new MutationObserver((mut, obs) => { called1 = true; Assert.AreEqual(1, mut.Length); }); observer1.Connect(document.DocumentElement, attributes: true, subtree: true); var observer2 = new MutationObserver((mut, obs) => { called2 = true; Assert.AreEqual(0, mut.Length); }); observer2.Connect(document.DocumentElement, attributes: true, subtree: false); var observer3 = new MutationObserver((mut, obs) => { called3 = true; Assert.AreEqual(1, mut.Length); }); observer3.Connect(document.Body, attributes: true); document.Body.SetAttribute(attrName, attrValue); observer1.TriggerWith(observer1.Flush().ToArray()); observer2.TriggerWith(observer2.Flush().ToArray()); observer3.TriggerWith(observer3.Flush().ToArray()); Assert.IsTrue(called1); Assert.IsTrue(called2); Assert.IsTrue(called3); }
public void ConnectMutationObserverTextNoDescendentsButCreatedTriggerManually() { var called = false; var text = "something"; var observer = new MutationObserver((mut, obs) => { called = true; Assert.AreEqual(1, mut.Length); Assert.AreEqual(1, mut[0].Added.Length); Assert.AreEqual(text, mut[0].Added[0].TextContent); }); var document = Html(""); observer.Connect(document.Body, subtree: false, childList: true); document.Body.TextContent = text; Assert.IsTrue(called); }