Пример #1
0
        /// <summary>
        /// Removes a child from the collection of children.
        /// </summary>
        /// <param name="node">The child to remove.</param>
        /// <param name="suppressObservers">If mutation observers should be surpressed.</param>
        internal void RemoveChild(Node node, Boolean suppressObservers)
        {
            var index = _children.Index(node);

            _owner.ForEachRange(m => m.Head.IsInclusiveDescendantOf(node), m => m.StartWith(this, index));
            _owner.ForEachRange(m => m.Tail.IsInclusiveDescendantOf(node), m => m.EndWith(this, index));
            _owner.ForEachRange(m => m.Head == this && m.Start > index, m => m.StartWith(this, m.Start - 1));
            _owner.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)
            {
                var removedNodes = new NodeList();
                removedNodes.Add(node);

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

                //TODO Mutation
                // For each ancestor ancestor of node, if ancestor has any registered observers whose options's subtree is true,
                // then for each such registered observer registered, append a transient registered observer whose observer and
                // options are identical to those of registered and source which is registered to node's list of registered observers.
            }

            RemoveNode(index, node);
            NodeIsRemoved(node, oldPreviousSibling);
        }
Пример #2
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(ErrorCode.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));
        }
Пример #3
0
        internal void AttributeChanged(String localName, String namespaceUri, String oldValue)
        {
            Action <String> handler = null;

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

            Owner.QueueMutation(MutationRecord.Attributes(
                                    target: this,
                                    attributeName: localName,
                                    attributeNamespace: namespaceUri,
                                    previousValue: oldValue));
        }
Пример #4
0
        /// <summary>
        /// Replaces all nodes with the given node, if any.
        /// </summary>
        /// <param name="node">The node to insert, if any.</param>
        /// <param name="suppressObservers">If mutation observers should be surpressed.</param>
        internal void ReplaceAll(Node node, Boolean suppressObservers)
        {
            if (node != null)
            {
                _owner.AdoptNode(node);
            }

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

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

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

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

            _owner.QueueMutation(MutationRecord.ChildList(
                                     target: this,
                                     addedNodes: addedNodes,
                                     removedNodes: removedNodes));
        }
Пример #5
0
 public void Enqueue(MutationRecord record)
 {
     //TODO Mutation
     //1. Let interested observers be an initially empty set of MutationObserver objects optionally paired with a string.
     //2. Let nodes be the inclusive ancestors of target.
     //3. Then, for each node in nodes, and then for each registered observer (with registered observer's options as options) in node's list of registered observers:
     //3.1 If node is not target and options's subtree is false, continue.
     //3.2 If type is "attributes" and options's attributes is not true, continue.
     //3.3 If type is "attributes", options's attributeFilter is present, and either options's attributeFilter does not contain name or namespace is non-null, continue.
     //3.4 If type is "characterData" and options's characterData is not true, continue.
     //3.5 If type is "childList" and options's childList is false, continue.
     //3.6 If registered observer's observer is not in interested observers, append registered observer's observer to interested observers.
     //3.7 If either type is "attributes" and options's attributeOldValue is true, or type is "characterData" and options's characterDataOldValue is true, set the paired string of registered observer's observer in interested observers to oldValue.
     //4. Then, for each observer in interested observers:
     //4.1 Let record be a new MutationRecord object with its type set to type and target set to target.
     //4.2 If name and namespace are given, set record's attributeName to name, and record's attributeNamespace to namespace.
     //4.3 If addedNodes is given, set record's addedNodes to addedNodes.
     //4.4 If removedNodes is given, set record's removedNodes to removedNodes,
     //4.5 If previousSibling is given, set record's previousSibling to previousSibling.
     //4.6 If nextSibling is given, set record's nextSibling to nextSibling.
     //4.7 If observer has a paired string, set record's oldValue to observer's paired string.
     //4.8 Append record to observer's record queue.
     //5. Queue a mutation observer compound microtask.
 }
Пример #6
0
        /// <summary>
        /// Replaces one child node of the specified element with another.
        /// </summary>
        /// <param name="node">The new node to replace oldChild. If it already exists in the DOM, it is first removed.</param>
        /// <param name="child">The existing child to be replaced.</param>
        /// <param name="suppressObservers">If mutation observers should be surpressed.</param>
        /// <returns>The replaced node. This is the same node as oldChild.</returns>
        internal INode ReplaceChild(Node node, Node child, Boolean suppressObservers)
        {
            if (_type != NodeType.Document && _type != NodeType.DocumentFragment && _type != NodeType.Element)
            {
                throw new DomException(ErrorCode.HierarchyRequest);
            }
            else if (node.IsHostIncludingInclusiveAncestor(this))
            {
                throw new DomException(ErrorCode.HierarchyRequest);
            }
            else if (child.Parent != this)
            {
                throw new DomException(ErrorCode.NotFound);
            }

            if (node is IElement || node is ICharacterData || node is IDocumentFragment || node is IDocumentType)
            {
                var document = _parent as IDocument;

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

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

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

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

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

                var referenceChild = child.NextSibling;

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

                _owner.AdoptNode(node);
                RemoveChild(child, true);
                InsertBefore(node, referenceChild, true);
                var addedNodes   = new NodeList();
                var removedNodes = new NodeList();
                removedNodes.Add(child);

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

                _owner.QueueMutation(MutationRecord.ChildList(
                                         target: this,
                                         addedNodes: addedNodes,
                                         removedNodes: removedNodes,
                                         previousSibling:
                                         child.PreviousSibling,
                                         nextSibling: referenceChild));

                return(child);
            }
            else
            {
                throw new DomException(ErrorCode.HierarchyRequest);
            }
        }