Example #1
0
        //TODO: implement real implicit closing logic from HTML5 spec
        // see http://www.w3.org/html/wg/drafts/html/master/syntax.html#syntax-tag-omission
        public static bool IsImplicitlyClosedBy(this XElement parent, INamedXObject current)
        {
            //inline and paragraph tags are implicitly closed by block tags and paragraph tags
            if (ElementTypes.IsInline(parent.Name.Name) || ElementTypes.IsParagraph(parent.Name.Name))
            {
                return(ElementTypes.IsBlock(current.Name.Name) || ElementTypes.IsParagraph(current.Name.Name));
            }

            return(false);
        }
        public override State PushChar(char c, MonoDevelop.Xml.StateEngine.IParseContext context, ref string rollback)
        {
            //NOTE: This is (mostly) duplicated in HtmlTagState
            //handle "paragraph" tags implicitly closed by block-level elements
            if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState)
            {
                XClosingTag ct = (XClosingTag)context.Nodes.Peek();
                //Note: the node stack will always be at least 1 deep due to the XDocument
                XElement parent = context.Nodes.Peek(1) as XElement;


                while (parent != null && parent.Name.IsValid && !parent.Name.HasPrefix && !ct.Name.HasPrefix &&
                       ct.Name.IsValid &&
                       string.Compare(ct.Name.Name, parent.Name.Name, StringComparison.OrdinalIgnoreCase) != 0 &&
                       !ElementTypes.IsInline(ct.Name.Name) &&
                       (ElementTypes.IsInline(parent.Name.Name) || ElementTypes.IsParagraph(parent.Name.Name))
                       )
                {
                    context.Nodes.Pop();
                    context.Nodes.Pop();
                    if (warnAutoClose)
                    {
                        context.LogWarning(string.Format("Tag '{0}' implicitly closed by closing tag '{1}'.",
                                                         parent.Name.Name, ct.Name.Name), parent.Region);
                    }
                    //parent.Region.End = element.Region.Start;
                    //parent.Region.End.Column = Math.Max (parent.Region.End.Column - 1, 1);
                    parent.Close(parent);
                    context.Nodes.Push(ct);

                    parent = context.Nodes.Peek(1) as XElement;
                }
            }

            return(base.PushChar(c, context, ref rollback));
        }
        public override State PushChar(char c, IParseContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 0 && context.PreviousState is HtmlScriptBodyState)
            {
                return(Parent);
            }

            //NOTE: This is (mostly) duplicated in HtmlClosingTagState
            //handle "paragraph" tags implicitly closed by block-level elements
            if (context.CurrentStateLength == 1 && context.PreviousState is XmlNameState)
            {
                XElement element = (XElement)context.Nodes.Peek();
                //Note: the node stack will always be at least 1 deep due to the XDocument
                XElement parent = context.Nodes.Peek(1) as XElement;

                while (parent != null && parent.Name.IsValid && !parent.Name.HasPrefix && !element.Name.HasPrefix &&
                       element.Name.IsValid &&
                       !ElementTypes.IsInline(element.Name.Name) &&
                       (ElementTypes.IsInline(parent.Name.Name) || ElementTypes.IsParagraph(parent.Name.Name))
                       )
                {
                    context.Nodes.Pop();
                    context.Nodes.Pop();
                    if (warnAutoClose)
                    {
                        context.LogWarning(string.Format("Tag '{0}' implicitly closed by tag '{1}'.",
                                                         parent.Name.Name, element.Name.Name), parent.Region);
                    }
                    //parent.Region.End = element.Region.Start;
                    //parent.Region.End.Column = Math.Max (parent.Region.End.Column - 1, 1);
                    parent.Close(parent);
                    context.Nodes.Push(element);

                    parent = context.Nodes.Peek(1) as XElement;
                }
            }

            State ret = base.PushChar(c, context, ref rollback);

            if (ret == Parent && c == '>')
            {
                var element = context.Nodes.Peek() as XElement;
                if (element != null && !element.Name.HasPrefix && element.Name.IsValid)
                {
                    if (element.Name.Name.Equals("script", StringComparison.OrdinalIgnoreCase))
                    {
                        return(ScriptState);
                    }
                    else if (ElementTypes.IsEmpty(element.Name.Name))
                    {
                        element.Close(element);
                        context.Nodes.Pop();

                        if (warnAutoClose)
                        {
                            context.LogWarning(string.Format("Implicitly closed empty tag '{0}'", element.Name.Name),
                                               element.Region);
                        }
                    }
                }
            }

            return(ret);
        }