AngleSharp by Florian Rappl

<PackageReference Include="AngleSharp" Version="0.8.6" />

.NET API 1,174,016 bytes

 MutationObserver

public sealed class MutationObserver
MutationObserver provides developers a way to react to changes in a DOM.
using AngleSharp.Attributes; using AngleSharp.Extensions; using System; using System.Collections.Generic; namespace AngleSharp.Dom { [DomName("MutationObserver")] public sealed class MutationObserver { private sealed class MutationObserving { private readonly INode _target; private readonly MutationObserverInit _options; private readonly List<INode> _transientNodes; public INode Target => _target; public MutationObserverInit Options => _options; public List<INode> TransientNodes => _transientNodes; public MutationObserving(INode target, MutationObserverInit options) { _target = target; _options = options; _transientNodes = new List<INode>(); } } private readonly Queue<IMutationRecord> _records; private readonly MutationCallback _callback; private readonly List<MutationObserving> _observing; private MutationObserving this[INode node] { get { foreach (MutationObserving item in _observing) { if (object.ReferenceEquals(item.Target, node)) return item; } return null; } } [DomConstructor] public MutationObserver(MutationCallback callback) { if (callback == null) throw new ArgumentNullException("callback"); _records = new Queue<IMutationRecord>(); _callback = callback; _observing = new List<MutationObserving>(); } internal void Enqueue(MutationRecord record) { int count = _records.Count; _records.Enqueue(record); } internal void Trigger() { IMutationRecord[] array = _records.ToArray(); _records.Clear(); ClearTransients(); if (array.Length != 0) TriggerWith(array); } internal void TriggerWith(IMutationRecord[] records) { _callback(records, this); } internal MutationObserverInit ResolveOptions(INode node) { foreach (MutationObserving item in _observing) { if (object.ReferenceEquals(item.Target, node) || item.TransientNodes.Contains(node)) return item.Options; } return null; } internal void AddTransient(INode ancestor, INode node) { MutationObserving mutationObserving = this[ancestor]; if (mutationObserving != null && mutationObserving.Options.IsObservingSubtree) mutationObserving.TransientNodes.Add(node); } internal void ClearTransients() { foreach (MutationObserving item in _observing) { item.TransientNodes.Clear(); } } [DomName("disconnect")] public void Disconnect() { foreach (MutationObserving item in _observing) { Node node = (Node)item.Target; node.Owner.Mutations.Unregister(this); } _records.Clear(); } public void Connect(INode target, MutationObserverInit options) { Node node = target as Node; if (node != null) { if (options == null) options = new MutationObserverInit(); if (!options.IsExaminingOldCharacterData.HasValue) options.IsExaminingOldCharacterData = false; if (!options.IsExaminingOldAttributeValue.HasValue) options.IsExaminingOldAttributeValue = false; if (!options.IsObservingAttributes.HasValue) options.IsObservingAttributes = (options.IsExaminingOldAttributeValue.Value || options.AttributeFilters != null); if (!options.IsObservingCharacterData.HasValue) options.IsObservingCharacterData = (options.IsExaminingOldCharacterData.HasValue && options.IsExaminingOldCharacterData.Value); if (options.IsExaminingOldAttributeValue.Value && !options.IsObservingAttributes.Value) throw new DomException(DomError.TypeMismatch); if (options.AttributeFilters != null && !options.IsObservingAttributes.Value) throw new DomException(DomError.TypeMismatch); if (options.IsExaminingOldCharacterData.Value && !options.IsObservingCharacterData.Value) throw new DomException(DomError.TypeMismatch); if (!options.IsObservingChildNodes && !options.IsObservingCharacterData.Value && !options.IsObservingAttributes.Value) throw new DomException(DomError.Syntax); node.Owner.Mutations.Register(this); MutationObserving mutationObserving = this[target]; if (mutationObserving != null) { mutationObserving.TransientNodes.Clear(); _observing.Remove(mutationObserving); } _observing.Add(new MutationObserving(target, options)); } } [DomName("observe")] public void Connect(INode target, IDictionary<string, object> options) { if (options == null) throw new ArgumentNullException("options"); MutationObserverInit mutationObserverInit = new MutationObserverInit(); mutationObserverInit.AttributeFilters = (options.TryGet("attributeFilter") as IEnumerable<string>); mutationObserverInit.IsObservingAttributes = options.TryGet<bool>("attributes"); mutationObserverInit.IsObservingChildNodes = (options.TryGet<bool>("childList") ?? false); mutationObserverInit.IsObservingCharacterData = options.TryGet<bool>("characterData"); mutationObserverInit.IsObservingSubtree = (options.TryGet<bool>("subtree") ?? false); mutationObserverInit.IsExaminingOldAttributeValue = options.TryGet<bool>("attributeOldValue"); mutationObserverInit.IsExaminingOldCharacterData = options.TryGet<bool>("characterDataOldValue"); MutationObserverInit options2 = mutationObserverInit; Connect(target, options2); } [DomName("takeRecords")] public IEnumerable<IMutationRecord> Flush() { while (_records.Count > 0) { yield return _records.Dequeue(); } } } }