CloneNode() public method

public CloneNode ( Node node ) : Node
node Node
return Node
Beispiel #1
0
            public virtual void Parse(Lexer lexer, Node element, short mode)
            {
                Node node;
                TagCollection tt = lexer.Options.TagTable;

                if ((element.Tag.Model & ContentModel.EMPTY) != 0)
                {
                    return;
                }

                if (element.Tag == tt.TagA)
                {
                    if (element.Attributes == null)
                    {
                        Report.Warning(lexer, element.Parent, element, Report.DISCARDING_UNEXPECTED);
                        Node.DiscardElement(element);
                        return;
                    }
                }

                /*
                ParseInline is used for some block level elements like H1 to H6
                For such elements we need to insert inline emphasis tags currently
                on the inline stack. For Inline elements, we normally push them
                onto the inline stack provided they aren't implicit or OBJECT/APPLET.
                This test is carried out in PushInline and PopInline, see istack.c
                We don't push A or SPAN to replicate current browser behavior
                */
                if (((element.Tag.Model & ContentModel.BLOCK) != 0) || (element.Tag == tt.TagDt))
                {
                    lexer.InlineDup(null);
                }
                else if ((element.Tag.Model & ContentModel.INLINE) != 0 && element.Tag != tt.TagA &&
                         element.Tag != tt.TagSpan)
                {
                    lexer.PushInline(element);
                }

                if (element.Tag == tt.TagNobr)
                {
                    lexer.BadLayout |= Report.USING_NOBR;
                }
                else if (element.Tag == tt.TagFont)
                {
                    lexer.BadLayout |= Report.USING_FONT;
                }

                /* Inline elements may or may not be within a preformatted element */
                if (mode != Lexer.PREFORMATTED)
                {
                    mode = Lexer.MIXED_CONTENT;
                }

                while (true)
                {
                    node = lexer.GetToken(mode);
                    if (node == null)
                    {
                        break;
                    }
                    /* end tag for current element */
                    if (node.Tag == element.Tag && node.Type == Node.END_TAG)
                    {
                        if ((element.Tag.Model & ContentModel.INLINE) != 0 && element.Tag != tt.TagA)
                        {
                            lexer.PopInline(node);
                        }

                        if ((mode & Lexer.PREFORMATTED) == 0)
                        {
                            Node.TrimSpaces(lexer, element);
                        }
                        /*
                        if a font element wraps an anchor and nothing else
                        then move the font element inside the anchor since
                        otherwise it won't alter the anchor text color
                        */
                        if (element.Tag == tt.TagFont && element.Content != null && element.Content == element.Last)
                        {
                            Node child = element.Content;

                            if (child.Tag == tt.TagA)
                            {
                                child.Parent = element.Parent;
                                child.Next = element.Next;
                                child.Prev = element.Prev;

                                if (child.Prev != null)
                                {
                                    child.Prev.Next = child;
                                }
                                else
                                {
                                    child.Parent.Content = child;
                                }

                                if (child.Next != null)
                                {
                                    child.Next.Prev = child;
                                }
                                else
                                {
                                    child.Parent.Last = child;
                                }

                                element.Next = null;
                                element.Prev = null;
                                element.Parent = child;
                                element.Content = child.Content;
                                element.Last = child.Last;
                                child.Content = element;
                                child.Last = element;
                                for (child = element.Content; child != null; child = child.Next)
                                {
                                    child.Parent = element;
                                }
                            }
                        }
                        element.Closed = true;
                        Node.TrimSpaces(lexer, element);
                        Node.TrimEmptyElement(lexer, element);
                        return;
                    }

                    /* <u>...<u>  map 2nd <u> to </u> if 1st is explicit */
                    /* otherwise emphasis nesting is probably unintentional */
                    /* big and small have cumulative effect to leave them alone */
                    if (node.Type == Node.START_TAG && node.Tag == element.Tag && lexer.IsPushed(node) &&
                        !node.Isimplicit && !element.Isimplicit && node.Tag != null &&
                        ((node.Tag.Model & ContentModel.INLINE) != 0) && node.Tag != tt.TagA && node.Tag != tt.TagFont &&
                        node.Tag != tt.TagBig && node.Tag != tt.TagSmall)
                    {
                        if (element.Content != null && node.Attributes == null)
                        {
                            Report.Warning(lexer, element, node, Report.COERCE_TO_ENDTAG);
                            node.Type = Node.END_TAG;
                            lexer.UngetToken();
                            continue;
                        }

                        Report.Warning(lexer, element, node, Report.NESTED_EMPHASIS);
                    }

                    if (node.Type == Node.TEXT_NODE)
                    {
                        /* only called for 1st child */
                        if (element.Content == null && (mode & Lexer.PREFORMATTED) == 0)
                        {
                            Node.TrimSpaces(lexer, element);
                        }

                        if (node.Start >= node.End)
                        {
                            continue;
                        }

                        Node.InsertNodeAtEnd(element, node);
                        continue;
                    }

                    /* mixed content model so allow text */
                    if (Node.InsertMisc(element, node))
                    {
                        continue;
                    }

                    /* deal with HTML tags */
                    if (node.Tag == tt.TagHtml)
                    {
                        if (node.Type == Node.START_TAG || node.Type == Node.START_END_TAG)
                        {
                            Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
                            continue;
                        }

                        /* otherwise infer end of inline element */
                        lexer.UngetToken();
                        if ((mode & Lexer.PREFORMATTED) == 0)
                        {
                            Node.TrimSpaces(lexer, element);
                        }
                        Node.TrimEmptyElement(lexer, element);
                        return;
                    }

                    /* within <dt> or <pre> map <p> to <br> */
                    if (node.Tag == tt.TagP && node.Type == Node.START_TAG &&
                        ((mode & Lexer.PREFORMATTED) != 0 || element.Tag == tt.TagDt || element.IsDescendantOf(tt.TagDt)))
                    {
                        node.Tag = tt.TagBr;
                        node.Element = "br";
                        Node.TrimSpaces(lexer, element);
                        Node.InsertNodeAtEnd(element, node);
                        continue;
                    }

                    /* ignore unknown and PARAM tags */
                    if (node.Tag == null || node.Tag == tt.TagParam)
                    {
                        Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
                        continue;
                    }

                    if (node.Tag == tt.TagBr && node.Type == Node.END_TAG)
                    {
                        node.Type = Node.START_TAG;
                    }

                    if (node.Type == Node.END_TAG)
                    {
                        /* coerce </br> to <br> */
                        if (node.Tag == tt.TagBr)
                        {
                            node.Type = Node.START_TAG;
                        }
                        else if (node.Tag == tt.TagP)
                        {
                            /* coerce unmatched </p> to <br><br> */
                            if (!element.IsDescendantOf(tt.TagP))
                            {
                                Node.CoerceNode(lexer, node, tt.TagBr);
                                Node.TrimSpaces(lexer, element);
                                Node.InsertNodeAtEnd(element, node);
                                //node = lexer.InferredTag("br");
                                continue;
                            }
                        }
                        else if ((node.Tag.Model & ContentModel.INLINE) != 0 && node.Tag != tt.TagA &&
                                 (node.Tag.Model & ContentModel.OBJECT) == 0 &&
                                 (element.Tag.Model & ContentModel.INLINE) != 0)
                        {
                            /* allow any inline end tag to end current element */
                            lexer.PopInline(element);

                            if (element.Tag != tt.TagA)
                            {
                                if (node.Tag == tt.TagA && node.Tag != element.Tag)
                                {
                                    Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_BEFORE);
                                    lexer.UngetToken();
                                }
                                else
                                {
                                    Report.Warning(lexer, element, node, Report.NON_MATCHING_ENDTAG);
                                }

                                if ((mode & Lexer.PREFORMATTED) == 0)
                                {
                                    Node.TrimSpaces(lexer, element);
                                }
                                Node.TrimEmptyElement(lexer, element);
                                return;
                            }

                            /* if parent is <a> then discard unexpected inline end tag */
                            Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
                            continue;
                        }
                            /* special case </tr> etc. for stuff moved in front of table */
                        else if (lexer.Exiled && node.Tag.Model != 0 && (node.Tag.Model & ContentModel.TABLE) != 0)
                        {
                            lexer.UngetToken();
                            Node.TrimSpaces(lexer, element);
                            Node.TrimEmptyElement(lexer, element);
                            return;
                        }
                    }

                    /* allow any header tag to end current header */
                    if ((node.Tag.Model & ContentModel.HEADING) != 0 && (element.Tag.Model & ContentModel.HEADING) != 0)
                    {
                        if (node.Tag == element.Tag)
                        {
                            Report.Warning(lexer, element, node, Report.NON_MATCHING_ENDTAG);
                        }
                        else
                        {
                            Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_BEFORE);
                            lexer.UngetToken();
                        }
                        if ((mode & Lexer.PREFORMATTED) == 0)
                        {
                            Node.TrimSpaces(lexer, element);
                        }
                        Node.TrimEmptyElement(lexer, element);
                        return;
                    }

                    /*
                    an <A> tag to ends any open <A> element
                    but <A href=...> is mapped to </A><A href=...>
                    */
                    if (node.Tag == tt.TagA && !node.Isimplicit && lexer.IsPushed(node))
                    {
                        /* coerce <a> to </a> unless it has some attributes */
                        if (node.Attributes == null)
                        {
                            node.Type = Node.END_TAG;
                            Report.Warning(lexer, element, node, Report.COERCE_TO_ENDTAG);
                            lexer.PopInline(node);
                            lexer.UngetToken();
                            continue;
                        }

                        lexer.UngetToken();
                        Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_BEFORE);
                        lexer.PopInline(element);
                        if ((mode & Lexer.PREFORMATTED) == 0)
                        {
                            Node.TrimSpaces(lexer, element);
                        }
                        Node.TrimEmptyElement(lexer, element);
                        return;
                    }

                    if ((element.Tag.Model & ContentModel.HEADING) != 0)
                    {
                        if (node.Tag == tt.TagCenter || node.Tag == tt.TagDiv)
                        {
                            if (node.Type != Node.START_TAG && node.Type != Node.START_END_TAG)
                            {
                                Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
                                continue;
                            }

                            Report.Warning(lexer, element, node, Report.TAG_NOT_ALLOWED_IN);

                            /* insert center as parent if heading is empty */
                            if (element.Content == null)
                            {
                                Node.InsertNodeAsParent(element, node);
                                continue;
                            }

                            /* split heading and make center parent of 2nd part */
                            Node.InsertNodeAfterElement(element, node);

                            if ((mode & Lexer.PREFORMATTED) == 0)
                            {
                                Node.TrimSpaces(lexer, element);
                            }

                            element = lexer.CloneNode(element);
                            element.Start = lexer.Lexsize;
                            element.End = lexer.Lexsize;
                            Node.InsertNodeAtEnd(node, element);
                            continue;
                        }

                        if (node.Tag == tt.TagHr)
                        {
                            if (node.Type != Node.START_TAG && node.Type != Node.START_END_TAG)
                            {
                                Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
                                continue;
                            }

                            Report.Warning(lexer, element, node, Report.TAG_NOT_ALLOWED_IN);

                            /* insert hr before heading if heading is empty */
                            if (element.Content == null)
                            {
                                Node.InsertNodeBeforeElement(element, node);
                                continue;
                            }

                            /* split heading and insert hr before 2nd part */
                            Node.InsertNodeAfterElement(element, node);

                            if ((mode & Lexer.PREFORMATTED) == 0)
                            {
                                Node.TrimSpaces(lexer, element);
                            }

                            element = lexer.CloneNode(element);
                            element.Start = lexer.Lexsize;
                            element.End = lexer.Lexsize;
                            Node.InsertNodeAfterElement(node, element);
                            continue;
                        }
                    }

                    if (element.Tag == tt.TagDt)
                    {
                        if (node.Tag == tt.TagHr)
                        {
                            if (node.Type != Node.START_TAG && node.Type != Node.START_END_TAG)
                            {
                                Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
                                continue;
                            }

                            Report.Warning(lexer, element, node, Report.TAG_NOT_ALLOWED_IN);
                            Node dd = lexer.InferredTag("dd");

                            /* insert hr within dd before dt if dt is empty */
                            if (element.Content == null)
                            {
                                Node.InsertNodeBeforeElement(element, dd);
                                Node.InsertNodeAtEnd(dd, node);
                                continue;
                            }

                            /* split dt and insert hr within dd before 2nd part */
                            Node.InsertNodeAfterElement(element, dd);
                            Node.InsertNodeAtEnd(dd, node);

                            if ((mode & Lexer.PREFORMATTED) == 0)
                            {
                                Node.TrimSpaces(lexer, element);
                            }

                            element = lexer.CloneNode(element);
                            element.Start = lexer.Lexsize;
                            element.End = lexer.Lexsize;
                            Node.InsertNodeAfterElement(dd, element);
                            continue;
                        }
                    }

                    /*
                    if this is the end tag for an ancestor element
                    then infer end tag for this element
                    */
                    if (node.Type == Node.END_TAG)
                    {
                        Node parent;
                        for (parent = element.Parent; parent != null; parent = parent.Parent)
                        {
                            if (node.Tag == parent.Tag)
                            {
                                if ((element.Tag.Model & ContentModel.OPT) == 0 && !element.Isimplicit)
                                {
                                    Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_BEFORE);
                                }

                                if (element.Tag == tt.TagA)
                                {
                                    lexer.PopInline(element);
                                }

                                lexer.UngetToken();

                                if ((mode & Lexer.PREFORMATTED) == 0)
                                {
                                    Node.TrimSpaces(lexer, element);
                                }

                                Node.TrimEmptyElement(lexer, element);
                                return;
                            }
                        }
                    }

                    /* block level tags end this element */
                    if ((node.Tag.Model & ContentModel.INLINE) == 0)
                    {
                        if (node.Type != Node.START_TAG)
                        {
                            Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
                            continue;
                        }

                        if ((element.Tag.Model & ContentModel.OPT) == 0)
                        {
                            Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_BEFORE);
                        }

                        if ((node.Tag.Model & ContentModel.HEAD) != 0 && (node.Tag.Model & ContentModel.BLOCK) == 0)
                        {
                            MoveToHead(lexer, element, node);
                            continue;
                        }

                        /*
                        prevent anchors from propagating into block tags
                        except for headings h1 to h6
                        */
                        if (element.Tag == tt.TagA)
                        {
                            if (node.Tag != null && (node.Tag.Model & ContentModel.HEADING) == 0)
                            {
                                lexer.PopInline(element);
                            }
                            else if (element.Content == null)
                            {
                                Node.DiscardElement(element);
                                lexer.UngetToken();
                                return;
                            }
                        }

                        lexer.UngetToken();

                        if ((mode & Lexer.PREFORMATTED) == 0)
                        {
                            Node.TrimSpaces(lexer, element);
                        }

                        Node.TrimEmptyElement(lexer, element);
                        return;
                    }

                    /* parse inline element */
                    if (node.Type == Node.START_TAG || node.Type == Node.START_END_TAG)
                    {
                        if (node.Isimplicit)
                        {
                            Report.Warning(lexer, element, node, Report.INSERTING_TAG);
                        }

                        /* trim white space before <br> */
                        if (node.Tag == tt.TagBr)
                        {
                            Node.TrimSpaces(lexer, element);
                        }

                        Node.InsertNodeAtEnd(element, node);
                        ParseTag(lexer, node, mode);
                        continue;
                    }

                    /* discard unexpected tags */
                    Report.Warning(lexer, element, node, Report.DISCARDING_UNEXPECTED);
                }

                if ((element.Tag.Model & ContentModel.OPT) == 0)
                {
                    Report.Warning(lexer, element, node, Report.MISSING_ENDTAG_FOR);
                }

                Node.TrimEmptyElement(lexer, element);
            }