AngleSharp by Florian Rappl

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

.NET API 1,171,968 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.Collections.Generic; namespace AngleSharp.Dom { [DomName("MutationObserver")] public sealed class MutationObserver { private 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 (item.Target == node) return item; } return null; } } [DomConstructor] public MutationObserver(MutationCallback 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 (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)item.Target).Owner.Mutations.Unregister(this); } _records.Clear(); } public void Connect(INode target, MutationObserverInit options) { Node node = target as Node; if (node != null) { 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(ErrorCode.TypeMismatch); if (options.AttributeFilters != null && !options.IsObservingAttributes.Value) throw new DomException(ErrorCode.TypeMismatch); if (options.IsExaminingOldCharacterData.Value && !options.IsObservingCharacterData.Value) throw new DomException(ErrorCode.TypeMismatch); if (!options.IsObservingChildNodes && !options.IsObservingCharacterData.Value && !options.IsObservingAttributes.Value) throw new DomException(ErrorCode.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) { 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"); Connect(target, mutationObserverInit); } [DomName("takeRecords")] public IEnumerable<IMutationRecord> Flush() { while (_records.Count > 0) { yield return _records.Dequeue(); } } } }