Esempio n. 1
0
        /// <summary>
        /// Replaces some data starting at the given offset with the given
        /// length.
        /// </summary>
        /// <param name="offset">The start index.</param>
        /// <param name="count">The length of the replacement.</param>
        /// <param name="data">The data to insert at the replacement.</param>
        public void Replace(Int32 offset, Int32 count, String data)
        {
            var owner  = Owner;
            var length = _content.Length;

            if (offset > length)
            {
                throw new DomException(DomError.IndexSizeError);
            }

            if (offset + count > length)
            {
                count = length - offset;
            }

            owner.QueueMutation(MutationRecord.CharacterData(target: this, previousValue: _content));

            var deleteOffset = offset + data.Length;

            _content = _content.Insert(offset, data).Remove(deleteOffset, count);

            owner.ForEachRange(m => m.Head == this && m.Start > offset && m.Start <= offset + count, m => m.StartWith(this, offset));
            owner.ForEachRange(m => m.Tail == this && m.End > offset && m.End <= offset + count, m => m.EndWith(this, offset));
            owner.ForEachRange(m => m.Head == this && m.Start > offset + count, m => m.StartWith(this, m.Start + data.Length - count));
            owner.ForEachRange(m => m.Tail == this && m.End > offset + count, m => m.EndWith(this, m.End + data.Length - count));
        }
        internal void RemoveChild(Node node, Boolean suppressObservers)
        {
            var document = Owner;
            var index    = _children.Index(node);

            if (document != null)
            {
                document.ForEachRange(m => m.Head.IsInclusiveDescendantOf(node), m => m.StartWith(this, index));
                document.ForEachRange(m => m.Tail.IsInclusiveDescendantOf(node), m => m.EndWith(this, index));
                document.ForEachRange(m => m.Head == this && m.Start > index, m => m.StartWith(this, m.Start - 1));
                document.ForEachRange(m => m.Tail == this && m.End > index, m => m.EndWith(this, m.End - 1));
            }

            var oldPreviousSibling = index > 0 ? _children[index - 1] : null;

            if (!suppressObservers && document != null)
            {
                var removedNodes = new NodeList {
                    node
                };

                document.QueueMutation(MutationRecord.ChildList(
                                           target: this,
                                           removedNodes: removedNodes,
                                           previousSibling: oldPreviousSibling,
                                           nextSibling: node.NextSibling));

                document.AddTransientObserver(node);
            }

            RemoveNode(index, node);
            NodeIsRemoved(node, oldPreviousSibling);
        }
Esempio n. 3
0
        internal INode ReplaceChild(Node node, Node child, Boolean suppressObservers)
        {
            if (this.IsEndPoint() || node.IsHostIncludingInclusiveAncestor(this))
            {
                throw new DomException(DomError.HierarchyRequest);
            }

            if (child.Parent != this)
            {
                throw new DomException(DomError.NotFound);
            }

            if (node.IsInsertable())
            {
                var parent         = this as IDocument;
                var referenceChild = child.NextSibling;
                var document       = Owner;
                var addedNodes     = new NodeList();
                var removedNodes   = new NodeList();

                if (parent != null && IsChangeForbidden(node, parent, child))
                {
                    throw new DomException(DomError.HierarchyRequest);
                }

                if (Object.ReferenceEquals(referenceChild, node))
                {
                    referenceChild = node.NextSibling;
                }

                document?.AdoptNode(node);
                RemoveChild(child, true);
                InsertBefore(node, referenceChild, true);
                removedNodes.Add(child);

                if (node._type == NodeType.DocumentFragment)
                {
                    addedNodes.AddRange(node._children);
                }
                else
                {
                    addedNodes.Add(node);
                }

                if (!suppressObservers && document != null)
                {
                    document.QueueMutation(MutationRecord.ChildList(
                                               target: this,
                                               addedNodes: addedNodes,
                                               removedNodes: removedNodes,
                                               previousSibling: child.PreviousSibling,
                                               nextSibling: referenceChild));
                }

                return(child);
            }

            throw new DomException(DomError.HierarchyRequest);
        }
Esempio n. 4
0
 internal void AttributeChanged(String localName, String namespaceUri, String oldValue)
 {
     Owner.QueueMutation(MutationRecord.Attributes(
                             target: this,
                             attributeName: localName,
                             attributeNamespace: namespaceUri,
                             previousValue: oldValue));
 }
        /// <summary>
        /// Queues a record.
        /// </summary>
        /// <param name="record">The record to queue up.</param>
        internal void Enqueue(MutationRecord record)
        {
            if (_records.Count > 0)
            {
                //Here we could schedule a callback!
            }

            _records.Enqueue(record);
        }
Esempio n. 6
0
        /// <summary>
        /// Queues a record.
        /// </summary>
        /// <param name="record">The record to queue up.</param>
        internal void Enqueue(MutationRecord record)
        {
            if (_records.Count > 0)
            {
                //Here we could schedule a callback!
            }

            _records.Enqueue(record);
        }
Esempio n. 7
0
        /// <summary>
        /// Queues a mutation record for the corresponding observers.
        /// </summary>
        /// <param name="document">The document to use.</param>
        /// <param name="record">The record to enqueue.</param>
        public static void QueueMutation(this Document document, MutationRecord record)
        {
            if (document == null)
                return;

            var observers = document.Mutations.Observers.ToArray();

            if (observers.Length == 0)
                return;

            var nodes = record.Target.GetInclusiveAncestors();

            for (var i = 0; i < observers.Length; i++)
            {
                var observer = observers[i];
                var clearPreviousValue = default(bool?);

                foreach (var node in nodes)
                {
                    var options = observer.ResolveOptions(node);

                    if (options.IsInvalid)
                        continue;
                    else if (node != record.Target && options.IsObservingSubtree == false)
                        continue;
                    else if (record.IsAttribute && options.IsObservingAttributes == false)
                        continue;
                    else if (record.IsAttribute && options.AttributeFilters != null && (options.AttributeFilters.Contains(record.AttributeName) == false || record.AttributeNamespace != null))
                        continue;
                    else if (record.IsCharacterData && options.IsObservingCharacterData == false)
                        continue;
                    else if (record.IsChildList && options.IsObservingChildNodes == false)
                        continue;

                    if (clearPreviousValue.HasValue == false || clearPreviousValue.Value == true)
                    {
                        clearPreviousValue = (record.IsAttribute && options.IsExaminingOldAttributeValue == false) ||
                            (record.IsCharacterData && options.IsExaminingOldCharacterData == false);
                    }
                }

                if (clearPreviousValue == null)
                    continue;

                observer.Enqueue(record.Copy(clearPreviousValue.Value));
            }

            document.PerformMicrotaskCheckpoint();
        }
Esempio n. 8
0
        internal void AttributeChanged(String localName, String namespaceUri, String oldValue, String newValue)
        {
            var callback = GetOrCreateCallback(GetType());

            if (namespaceUri == null)
            {
                callback.Invoke(this, localName, newValue);
            }

            Owner.QueueMutation(MutationRecord.Attributes(
                                    target: this,
                                    attributeName: localName,
                                    attributeNamespace: namespaceUri,
                                    previousValue: oldValue));
        }
Esempio n. 9
0
        internal void AttributeChanged(String localName, String namespaceUri, String oldValue, String newValue)
        {
            if (namespaceUri == null)
            {
                foreach (var observer in Owner.Options.GetServices <IAttributeObserver>())
                {
                    observer.NotifyChange(this, localName, newValue);
                }
            }

            Owner.QueueMutation(MutationRecord.Attributes(
                                    target: this,
                                    attributeName: localName,
                                    attributeNamespace: namespaceUri,
                                    previousValue: oldValue));
        }
        internal void ReplaceAll(Node node, Boolean suppressObservers)
        {
            var document = Owner;

            if (node != null)
            {
                document.AdoptNode(node);
            }

            var removedNodes = new NodeList();
            var addedNodes   = new NodeList();

            removedNodes.AddRange(_children);

            if (node != null)
            {
                if (node.NodeType == NodeType.DocumentFragment)
                {
                    addedNodes.AddRange(node._children);
                }
                else
                {
                    addedNodes.Add(node);
                }
            }

            for (var i = 0; i < removedNodes.Length; i++)
            {
                RemoveChild(removedNodes[i], true);
            }

            for (var i = 0; i < addedNodes.Length; i++)
            {
                InsertBefore(addedNodes[i], null, true);
            }

            if (!suppressObservers)
            {
                document.QueueMutation(MutationRecord.ChildList(
                                           target: this,
                                           addedNodes: addedNodes,
                                           removedNodes: removedNodes));
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Queues a mutation record for the corresponding observers.
        /// </summary>
        /// <param name="document">The document to use.</param>
        /// <param name="record">The record to enqueue.</param>
        internal static void QueueMutation(this Document document, MutationRecord record)
        {
            var observers = document.Mutations.Observers.ToArray();

            if (observers.Length > 0)
            {
                var nodes = record.Target.GetInclusiveAncestors();

                for (var i = 0; i < observers.Length; i++)
                {
                    var observer           = observers[i];
                    var clearPreviousValue = default(Boolean?);

                    foreach (var node in nodes)
                    {
                        var options = observer.ResolveOptions(node);

                        if (options.IsInvalid ||
                            (node != record.Target && !options.IsObservingSubtree) ||
                            (record.IsAttribute && !options.IsObservingAttributes) ||
                            (record.IsAttribute && options.AttributeFilters != null && (!options.AttributeFilters.Contains(record.AttributeName) || record.AttributeNamespace != null)) ||
                            (record.IsCharacterData && !options.IsObservingCharacterData) ||
                            (record.IsChildList && !options.IsObservingChildNodes))
                        {
                            continue;
                        }

                        if (!clearPreviousValue.HasValue || clearPreviousValue.Value)
                        {
                            clearPreviousValue = (record.IsAttribute && !options.IsExaminingOldAttributeValue) ||
                                                 (record.IsCharacterData && !options.IsExaminingOldCharacterData);
                        }
                    }

                    if (clearPreviousValue != null)
                    {
                        observer.Enqueue(record.Copy(clearPreviousValue.Value));
                    }
                }

                document.PerformMicrotaskCheckpoint();
            }
        }
Esempio n. 12
0
        internal void AttributeChanged(String localName, String namespaceUri, String oldValue, Boolean suppressMutationObservers = false)
        {
            Action <String> handler = null;

            if (_attributeHandlers.TryGetValue(localName, out handler))
            {
                var attr = _attributes.Get(localName);
                handler(attr != null ? attr.Value : null);
            }

            if (!suppressMutationObservers)
            {
                Owner.QueueMutation(MutationRecord.Attributes(
                                        target: this,
                                        attributeName: localName,
                                        attributeNamespace: namespaceUri,
                                        previousValue: oldValue));
            }
        }
        internal INode ReplaceChild(Node node, Node child, Boolean suppressObservers)
        {
            if (this.IsEndPoint() || node.IsHostIncludingInclusiveAncestor(this))
            {
                throw new DomException(DomError.HierarchyRequest);
            }

            if (child.Parent != this)
            {
                throw new DomException(DomError.NotFound);
            }

            if (node.IsInsertable())
            {
                var parent         = _parent as IDocument;
                var referenceChild = child.NextSibling;
                var document       = Owner;
                var addedNodes     = new NodeList();
                var removedNodes   = new NodeList();

                if (parent != null)
                {
                    var forbidden = false;

                    switch (node._type)
                    {
                    case NodeType.DocumentType:
                        forbidden = parent.Doctype != child || child.IsPrecededByElement();
                        break;

                    case NodeType.Element:
                        forbidden = parent.DocumentElement != child || child.IsFollowedByDoctype();
                        break;

                    case NodeType.DocumentFragment:
                        var elements = node.GetElementCount();
                        forbidden = elements > 1 || node.HasTextNodes() || (elements == 1 && (parent.DocumentElement != child || child.IsFollowedByDoctype()));
                        break;
                    }

                    if (forbidden)
                    {
                        throw new DomException(DomError.HierarchyRequest);
                    }
                }

                if (referenceChild == node)
                {
                    referenceChild = node.NextSibling;
                }

                document?.AdoptNode(node);
                RemoveChild(child, true);
                InsertBefore(node, referenceChild, true);
                removedNodes.Add(child);

                if (node._type == NodeType.DocumentFragment)
                {
                    addedNodes.AddRange(node._children);
                }
                else
                {
                    addedNodes.Add(node);
                }

                if (!suppressObservers && document != null)
                {
                    document.QueueMutation(MutationRecord.ChildList(
                                               target: this,
                                               addedNodes: addedNodes,
                                               removedNodes: removedNodes,
                                               previousSibling: child.PreviousSibling,
                                               nextSibling: referenceChild));
                }

                return(child);
            }

            throw new DomException(DomError.HierarchyRequest);
        }
        internal INode InsertBefore(Node newElement, Node referenceElement, Boolean suppressObservers)
        {
            var document = Owner;
            var count    = newElement.NodeType == NodeType.DocumentFragment ? newElement.ChildNodes.Length : 1;

            if (referenceElement != null && document != null)
            {
                var childIndex = referenceElement.Index();
                document.ForEachRange(m => m.Head == this && m.Start > childIndex, m => m.StartWith(this, m.Start + count));
                document.ForEachRange(m => m.Tail == this && m.End > childIndex, m => m.EndWith(this, m.End + count));
            }

            if (newElement.NodeType == NodeType.Document || newElement.Contains(this))
            {
                throw new DomException(DomError.HierarchyRequest);
            }

            var addedNodes = new NodeList();
            var n          = _children.Index(referenceElement);

            if (n == -1)
            {
                n = _children.Length;
            }

            if (newElement._type == NodeType.DocumentFragment)
            {
                var end   = n;
                var start = n;

                while (newElement.HasChildNodes)
                {
                    var child = newElement.ChildNodes[0];
                    newElement.RemoveChild(child, true);
                    InsertNode(end, child);
                    end++;
                }

                while (start < end)
                {
                    var child = _children[start];
                    addedNodes.Add(child);
                    NodeIsInserted(child);
                    start++;
                }
            }
            else
            {
                addedNodes.Add(newElement);
                InsertNode(n, newElement);
                NodeIsInserted(newElement);
            }

            if (!suppressObservers && document != null)
            {
                document.QueueMutation(MutationRecord.ChildList(
                                           target: this,
                                           addedNodes: addedNodes,
                                           previousSibling: n > 0 ? _children[n - 1] : null,
                                           nextSibling: referenceElement));
            }

            return(newElement);
        }