Example #1
0
		public TagInfo(string newTagName, TagInfo info) 
		{
			_tagName = newTagName;
			_inner = info.InnerWhiteSpaceType;
			_following = info.FollowingWhiteSpaceType;
			_flags = info.Flags;
			_type = info.Type;
		}
Example #2
0
 public FormatInfo(TagInfo info, bool isEnd)
 {
     tagInfo = info;
     isEndTag = isEnd;
 }
Example #3
0
        static HtmlFormatter()
        {
            commentTag = new TagInfo("", FormattingFlags.Comment | FormattingFlags.NoEndTag, WhiteSpaceType.CarryThrough, WhiteSpaceType.CarryThrough, ElementType.Any);
            directiveTag = new TagInfo("", FormattingFlags.NoEndTag, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Any);
            otherServerSideScriptTag = new TagInfo("", FormattingFlags.NoEndTag | FormattingFlags.Inline, ElementType.Any);
            unknownXmlTag = new TagInfo("", FormattingFlags.Xml, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Any);
            nestedXmlTag = new TagInfo("", FormattingFlags.AllowPartialTags, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Any);
            unknownHtmlTag = new TagInfo("", FormattingFlags.None, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Any);

            tagTable = new HybridDictionary(true);
            tagTable["a"] =  new TagInfo("a", FormattingFlags.Inline, ElementType.Inline);
            tagTable["acronym"] = new TagInfo("acronym", FormattingFlags.Inline, ElementType.Inline);
            tagTable["address"] = new TagInfo("address", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["applet"] = new TagInfo("applet", FormattingFlags.Inline, WhiteSpaceType.CarryThrough, WhiteSpaceType.Significant, ElementType.Inline);
            tagTable["area"] = new TagInfo("area", FormattingFlags.NoEndTag);
            tagTable["b"] = new TagInfo("b", FormattingFlags.Inline, ElementType.Inline);
            tagTable["base"] = new TagInfo("base", FormattingFlags.NoEndTag);
            tagTable["basefont"] = new TagInfo("basefont", FormattingFlags.NoEndTag, ElementType.Block);
            tagTable["bdo"] = new TagInfo("bdo", FormattingFlags.Inline, ElementType.Inline);
            tagTable["bgsound"] = new TagInfo("bgsound", FormattingFlags.NoEndTag);
            tagTable["big"] = new TagInfo("big", FormattingFlags.Inline, ElementType.Inline);
            tagTable["blink"] = new TagInfo("blink", FormattingFlags.Inline);
            tagTable["blockquote"] = new TagInfo("blockquote", FormattingFlags.Inline, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["body"] = new TagInfo("body", FormattingFlags.None);
            tagTable["br"] = new TagInfo("br", FormattingFlags.NoEndTag, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Inline);
            //tagTable["br"] = new TagInfo("br", FormattingFlags.NoEndTag, WhiteSpaceType.Significant, WhiteSpaceType.Significant, ElementType.Inline);
            tagTable["button"] = new TagInfo("button", FormattingFlags.Inline, ElementType.Inline);
            tagTable["caption"] = new TagInfo("caption", FormattingFlags.None);
            tagTable["cite"] = new TagInfo("cite", FormattingFlags.Inline, ElementType.Inline);
            tagTable["center"] = new TagInfo("center", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["code"] = new TagInfo("code", FormattingFlags.Inline, ElementType.Inline);
            tagTable["col"] = new TagInfo("col", FormattingFlags.NoEndTag);
            tagTable["colgroup"] = new TagInfo("colgroup", FormattingFlags.None);
            tagTable["dd"] = new TagInfo("dd", FormattingFlags.None);
            tagTable["del"] = new TagInfo("del", FormattingFlags.None);
            tagTable["dfn"] = new TagInfo("dfn", FormattingFlags.Inline, ElementType.Inline);
            tagTable["dir"] = new TagInfo("dir", FormattingFlags.None, ElementType.Block);
            tagTable["div"] = new TagInfo("div", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["dl"] = new TagInfo("dl", FormattingFlags.None, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["dt"] = new TagInfo("dt", FormattingFlags.Inline);
            tagTable["em"] = new TagInfo("em", FormattingFlags.Inline, ElementType.Inline);
            tagTable["embed"] = new TagInfo("embed", FormattingFlags.Inline, WhiteSpaceType.Significant, WhiteSpaceType.CarryThrough, ElementType.Inline);
            tagTable["fieldset"] = new TagInfo("fieldset", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["font"] = new TagInfo("font", FormattingFlags.Inline, ElementType.Inline);
            tagTable["form"] = new TagInfo("form", FormattingFlags.None, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["frame"] = new TagInfo("frame", FormattingFlags.NoEndTag);
            tagTable["frameset"] = new TagInfo("frameset", FormattingFlags.None);
            tagTable["head"] = new TagInfo("head", FormattingFlags.None, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant);
            tagTable["h1"] = new TagInfo("h1", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["h2"] = new TagInfo("h2", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["h3"] = new TagInfo("h3", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["h4"] = new TagInfo("h4", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["h5"] = new TagInfo("h5", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["h6"] = new TagInfo("h6", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            // REVIEW: <hr> was changed to be an Block element b/c IE appears to allow it.
            tagTable["hr"] = new TagInfo("hr", FormattingFlags.NoEndTag, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["html"] = new TagInfo("html", FormattingFlags.NoIndent, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant);
            tagTable["i"] = new TagInfo("i", FormattingFlags.Inline, ElementType.Inline);
            tagTable["iframe"] = new TagInfo("iframe", FormattingFlags.None, WhiteSpaceType.CarryThrough, WhiteSpaceType.NotSignificant, ElementType.Inline);
            tagTable["img"] = new TagInfo("img", FormattingFlags.Inline | FormattingFlags.NoEndTag, WhiteSpaceType.Significant, WhiteSpaceType.Significant, ElementType.Inline);
            tagTable["input"] = new TagInfo("input", FormattingFlags.NoEndTag, WhiteSpaceType.Significant, WhiteSpaceType.Significant, ElementType.Inline);
            tagTable["ins"] = new TagInfo("ins", FormattingFlags.None);
            tagTable["isindex"] = new TagInfo("isindex", FormattingFlags.None, WhiteSpaceType.NotSignificant, WhiteSpaceType.CarryThrough, ElementType.Block);
            tagTable["kbd"] = new TagInfo("kbd", FormattingFlags.Inline, ElementType.Inline);
            tagTable["label"] = new TagInfo("label", FormattingFlags.Inline, ElementType.Inline);
            tagTable["legend"] = new TagInfo("legend", FormattingFlags.None);
            tagTable["li"] = new LITagInfo();
            tagTable["link"] = new TagInfo("link", FormattingFlags.NoEndTag);
            tagTable["listing"] = new TagInfo("listing", FormattingFlags.None, WhiteSpaceType.CarryThrough, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["map"] = new TagInfo("map", FormattingFlags.Inline, ElementType.Inline);
            tagTable["marquee"] = new TagInfo("marquee", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["menu"] = new TagInfo("menu", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["meta"] = new TagInfo("meta", FormattingFlags.NoEndTag);
            tagTable["nobr"] = new TagInfo("nobr", FormattingFlags.Inline | FormattingFlags.NoEndTag, ElementType.Inline);
            tagTable["noembed"] = new TagInfo("noembed", FormattingFlags.None, ElementType.Block);
            tagTable["noframes"] = new TagInfo("noframes", FormattingFlags.None, ElementType.Block);
            tagTable["noscript"] = new TagInfo("noscript", FormattingFlags.None, ElementType.Block);
            tagTable["object"] = new TagInfo("object", FormattingFlags.None, ElementType.Inline);
            tagTable["ol"] = new OLTagInfo();
            tagTable["option"] = new TagInfo("option", FormattingFlags.None, WhiteSpaceType.Significant, WhiteSpaceType.CarryThrough);
            tagTable["p"] = new PTagInfo();
            tagTable["param"] = new TagInfo("param", FormattingFlags.NoEndTag);
            tagTable["pre"] = new TagInfo("pre", FormattingFlags.PreserveContent, WhiteSpaceType.CarryThrough, WhiteSpaceType.Significant, ElementType.Block);
            tagTable["q"] = new TagInfo("q", FormattingFlags.Inline, ElementType.Inline);
            tagTable["rt"] = new TagInfo("rt", FormattingFlags.None);
            tagTable["ruby"] = new TagInfo("ruby", FormattingFlags.None, ElementType.Inline);
            tagTable["s"] = new TagInfo("s", FormattingFlags.Inline, ElementType.Inline);
            tagTable["samp"] = new TagInfo("samp", FormattingFlags.None, ElementType.Inline);
            tagTable["script"] = new TagInfo("script", FormattingFlags.PreserveContent, WhiteSpaceType.CarryThrough, WhiteSpaceType.CarryThrough, ElementType.Inline);
            tagTable["select"] = new TagInfo("select", FormattingFlags.None, WhiteSpaceType.CarryThrough, WhiteSpaceType.Significant, ElementType.Block);
            tagTable["small"] = new TagInfo("small", FormattingFlags.Inline, ElementType.Inline);
            tagTable["span"] = new TagInfo("span", FormattingFlags.Inline, ElementType.Inline);
            tagTable["strike"] = new TagInfo("strike", FormattingFlags.Inline, ElementType.Inline);
            tagTable["strong"] = new TagInfo("strong", FormattingFlags.Inline, ElementType.Inline);
            tagTable["style"] = new TagInfo("style", FormattingFlags.PreserveContent, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Any);
            tagTable["sub"] = new TagInfo("sub", FormattingFlags.Inline, ElementType.Inline);
            tagTable["sup"] = new TagInfo("sup", FormattingFlags.Inline, ElementType.Inline);
            tagTable["table"] = new TagInfo("table", FormattingFlags.None, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["tbody"] = new TagInfo("tbody", FormattingFlags.None);
            tagTable["td"] = new TDTagInfo();
            tagTable["textarea"] = new TagInfo("textarea", FormattingFlags.Inline, WhiteSpaceType.CarryThrough, WhiteSpaceType.Significant, ElementType.Inline);
            tagTable["tfoot"] = new TagInfo("tfoot", FormattingFlags.None);
            tagTable["th"] = new TagInfo("th", FormattingFlags.None);
            tagTable["thead"] = new TagInfo("thead", FormattingFlags.None);
            tagTable["title"] = new TagInfo("title", FormattingFlags.Inline);
            tagTable["tr"] = new TRTagInfo();
            tagTable["tt"] = new TagInfo("tt", FormattingFlags.Inline, ElementType.Inline);
            tagTable["u"] = new TagInfo("u", FormattingFlags.Inline, ElementType.Inline);
            tagTable["ul"] = new TagInfo("ul", FormattingFlags.None, WhiteSpaceType.NotSignificant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["xml"] = new TagInfo("xml", FormattingFlags.Xml, WhiteSpaceType.Significant, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["xmp"] = new TagInfo("xmp", FormattingFlags.PreserveContent, WhiteSpaceType.CarryThrough, WhiteSpaceType.NotSignificant, ElementType.Block);
            tagTable["var"] = new TagInfo("var", FormattingFlags.Inline, ElementType.Inline);
            tagTable["wbr"] = new TagInfo("wbr", FormattingFlags.Inline | FormattingFlags.NoEndTag, ElementType.Inline);
        }
Example #4
0
        public void Format(string input, TextWriter output, HtmlFormatterOptions options)
        {
            // Determine if we are outputting xhtml
            bool makeXhtml = options.MakeXhtml;

            // Save the max line length
            int maxLineLength = options.MaxLineLength;

            // Make the indent string
            string indentString = new String(options.IndentChar, options.IndentSize);

            char[] chars = input.ToCharArray();
            Stack tagStack = new Stack();
            Stack writerStack = new Stack();

            // The previous begin or end tag that was seen
            FormatInfo previousTag = null;

            // The current begin or end tag that was seen
            FormatInfo currentTag = null;

            // The text between previousTag and currentTag
            string text = String.Empty;

            // True if we've seen whitespace at the end of the last text outputted
            bool sawWhiteSpace = false;

            // True if the last tag seen was self-terminated with a '/>'
            bool sawSelfTerminatingTag = false;

            // True if we saw a tag that we decided not to render
            bool ignoredLastTag = false;

            // Put the initial writer on the stack
            HtmlWriter writer = new HtmlWriter(output, indentString, maxLineLength);
            writerStack.Push(writer);

            Token t = HtmlTokenizer.GetFirstToken(chars);
            Token lastToken = t;

            while (t != null)
            {
                writer = (HtmlWriter)writerStack.Peek();
                switch (t.Type)
                {
                    case Token.AttrName:
                        if (makeXhtml)
                        {
                            string attrName = String.Empty;
                            if (!previousTag.tagInfo.IsXml)
                            {
                                // Need to lowercase the HTML attribute names for XHTML
                                attrName = t.Text.ToLower();
                            }
                            else
                            {
                                attrName = t.Text;
                            }
                            writer.Write(attrName);

                            // If we are trying to be compliant XHTML, don't allow attribute minimization
                            Token nextToken = HtmlTokenizer.GetNextToken(t);
                            if (nextToken.Type != Token.EqualsChar)
                            {
                                writer.Write("=\"" + attrName + "\"");
                            }
                        }
                        else
                        {
                            // Convert the case of the attribute if the tag isn't xml
                            if (!previousTag.tagInfo.IsXml)
                            {
                                if (options.AttributeCasing == HtmlFormatterCase.UpperCase)
                                {
                                    writer.Write(t.Text.ToUpper());
                                }
                                else if (options.AttributeCasing == HtmlFormatterCase.LowerCase)
                                {
                                    writer.Write(t.Text.ToLower());
                                }
                                else
                                {
                                    writer.Write(t.Text);
                                }
                            }
                            else
                            {
                                writer.Write(t.Text);
                            }
                        }
                        break;
                    case Token.AttrVal:
                        if (makeXhtml && (lastToken.Type != Token.DoubleQuote) && (lastToken.Type != Token.SingleQuote))
                        {
                            // If the attribute value isn't quoted, double quote it, replacing the inner double quotes
                            writer.Write('\"');
                            writer.Write(t.Text.Replace("\"", "&quot;"));
                            writer.Write('\"');
                        }
                        else
                        {
                            writer.Write(t.Text);
                        }
                        break;
                    case Token.CloseBracket:
                        if (makeXhtml)
                        {
                            if (ignoredLastTag)
                            {
                                // Don't render the close bracket if we ignored the last tag
                                ignoredLastTag = false;
                            }
                            else
                            {
                                if (sawSelfTerminatingTag && (!previousTag.tagInfo.IsComment))
                                {
                                    // If we saw a self terminating tag, that doesn't have the forward slash, put it in (except for comments)
                                    writer.Write(" />");
                                }
                                else
                                {
                                    // If we are just closing a normal tag, just put in a normal close bracket
                                    writer.Write('>');
                                }
                            }
                        }
                        else
                        {
                            // If there's no XHTML to be made, just put in a normal close bracket
                            writer.Write('>');
                        }
                        break;
                    case Token.DoubleQuote:
                        writer.Write('\"');
                        break;
                    case Token.Empty:
                        break;
                    case Token.EqualsChar:
                        writer.Write('=');
                        break;
                    case Token.Error:
                        if (lastToken.Type == Token.OpenBracket)
                        {
                            // Since we aren't outputting open brackets right away, we might have to output one now
                            writer.Write('<');
                        }
                        writer.Write(t.Text);
                        break;
                    case Token.ForwardSlash:
                    case Token.OpenBracket:
                        // Just push these symbols on the stack for now... output them when we write the tag
                        break;
                    case Token.SelfTerminating:
                        previousTag.isEndTag = true;
                        if (!previousTag.tagInfo.NoEndTag)
                        {
                            // If the tag that is self-terminating is normally not a self-closed tag
                            // then we've placed an entry on the stack for it.  Since it's self terminating, we now need
                            // to pop that item off of the tag stack
                            tagStack.Pop();

                            // If it was a self-closed Xml tag, then we also need to clean up the writerStack
                            if (previousTag.tagInfo.IsXml)
                            {
                                HtmlWriter oldWriter = (HtmlWriter)writerStack.Pop();
                                writer = (HtmlWriter)writerStack.Peek();

                                // Since a self-closed xml tag can't have any text content, we can just write out the formatted contents
                                writer.Write(oldWriter.Content);
                            }
                        }
                        if ((lastToken.Type == Token.Whitespace) && (lastToken.Text.Length > 0))
                        {
                            writer.Write("/>");
                        }
                        else
                        {
                            writer.Write(" />");
                        }
                        break;
                    case Token.SingleQuote:
                        writer.Write('\'');
                        break;
                    case Token.XmlDirective:
                        writer.WriteLineIfNotOnNewLine();
                        writer.Write('<');
                        writer.Write(t.Text);
                        writer.Write('>');
                        writer.WriteLineIfNotOnNewLine();
                        ignoredLastTag = true;
                        break;
                    case Token.TagName:
                    case Token.Comment:
                    case Token.InlineServerScript:
                        string tagName;

                        // Reset the self terminating tag flag
                        sawSelfTerminatingTag = false;

                        // Create or get the proper tagInfo, depending on the type of token
                        TagInfo info;
                        if (t.Type == Token.Comment)
                        {
                            // Handle comment tags
                            tagName = t.Text;
                            info = new TagInfo(t.Text, commentTag);
                        }
                        else if (t.Type == Token.InlineServerScript)
                        {
                            // Handle server-side script tags
                            string script = t.Text.Trim();
                            script = script.Substring(1);
                            tagName = script;
                            if (script.StartsWith("%@"))
                            {
                                // Directives are block tags
                                info = new TagInfo(script, directiveTag);
                            }
                            else
                            {
                                // Other server side script tags aren't
                                info = new TagInfo(script, otherServerSideScriptTag);
                            }
                        }
                        else
                        {
                            // Otherwise, this is a normal tag, and try to get a TagInfo for it
                            tagName = t.Text;
                            info = tagTable[tagName] as TagInfo;
                            if (info == null)
                            {
                                // if we couldn't find one, create a copy of the unknownTag with a new tagname
                                if (tagName.IndexOf(':') > -1)
                                {
                                    // If it is a prefixed tag, it's probably unknown XML
                                    info = new TagInfo(tagName, unknownXmlTag);
                                }
                                else if (writer is XmlWriter)
                                {
                                    info = new TagInfo(tagName, nestedXmlTag);
                                }
                                else
                                {
                                    // If it is a not prefixed, it's probably an unknown HTML tag
                                    info = new TagInfo(tagName, unknownHtmlTag);
                                }
                            }
                            else
                            {
                                // If it's not an unknown tag, converting to the desired case (and leave as is for PreserveCase)
                                if ((options.ElementCasing == HtmlFormatterCase.LowerCase) || makeXhtml)
                                {
                                    tagName = info.TagName;
                                }
                                else if (options.ElementCasing == HtmlFormatterCase.UpperCase)
                                {
                                    tagName = info.TagName.ToUpper();
                                }
                            }
                        }

                        if (previousTag == null)
                        {
                            // Special case for the first tag seen
                            previousTag = new FormatInfo(info, false);
                            // Since this is the first tag, set it's indent to 0
                            previousTag.indent = 0;

                            // Push it on the stack
                            tagStack.Push(previousTag);
                            // And output the preceeding text
                            writer.Write(text);

                            if (info.IsXml)
                            {
                                // When we encounter an xml block, create a new writer to contain the inner content of the xml
                                HtmlWriter newWriter = new XmlWriter(writer.Indent, info.TagName, indentString, maxLineLength);
                                writerStack.Push(newWriter);
                                writer = newWriter;
                            }

                            if (lastToken.Type == Token.ForwardSlash)
                            {
                                // If this is an end tag, output the proper prefix
                                writer.Write("</");
                            }
                            else
                            {
                                writer.Write('<');
                            }
                            // Write the name
                            writer.Write(tagName);
                            // Indicate that we've written out the last text block
                            text = String.Empty;
                        }
                        else
                        {
                            // Put the new tag in the next spot
                            currentTag = new FormatInfo(info, (lastToken.Type == Token.ForwardSlash));

                            WhiteSpaceType whiteSpaceType;
                            if (previousTag.isEndTag)
                            {
                                // If the previous tag is an end tag, we need to check the following whitespace
                                whiteSpaceType = previousTag.tagInfo.FollowingWhiteSpaceType;
                            }
                            else
                            {
                                // otherwise check the initial inner whitespace
                                whiteSpaceType = previousTag.tagInfo.InnerWhiteSpaceType;
                            }

                            // Flag that indicates if the previous tag (before the text) is an inline tag
                            bool inline = previousTag.tagInfo.IsInline;
                            bool emptyXml = false;
                            bool firstOrLastUnknownXmlText = false;

                            if (writer is XmlWriter)
                            {
                                // if we're in an xml block
                                XmlWriter xmlWriter = (XmlWriter)writer;

                                if (xmlWriter.IsUnknownXml)
                                {
                                    // Special case for unknown XML tags
                                    // Determine if this is the first or last xml text in an unknown xml tag, so we know to preserve the text content here
                                    firstOrLastUnknownXmlText = (((previousTag.isBeginTag) && (previousTag.tagInfo.TagName.ToLower() == xmlWriter.TagName.ToLower())) ||
                                        ((currentTag.isEndTag) && (currentTag.tagInfo.TagName.ToLower() == xmlWriter.TagName.ToLower()))) &&
                                        (!FormattedTextWriter.IsWhiteSpace(text));
                                }

                                if (previousTag.isBeginTag)
                                {
                                    if (FormattedTextWriter.IsWhiteSpace(text))
                                    {
                                        if ((xmlWriter.IsUnknownXml) && (currentTag.isEndTag) &&
                                            (previousTag.tagInfo.TagName.ToLower() == currentTag.tagInfo.TagName.ToLower()))
                                        {
                                            // Special case for unknown XML tags:
                                            // If the previous tag is an open tag and the next tag is the corresponding close tag and the text is only whitespace, also
                                            // treat the tag as inline, so the begin and end tag appear on the same line
                                            inline = true;
                                            emptyXml = true;
                                            // Empty the text since we want the open and close tag to be touching
                                            text = "";
                                        }
                                    }
                                    else
                                    {
                                        if (!xmlWriter.IsUnknownXml)
                                        {
                                            // If there is non-whitespace text and we're in a normal Xml block, then remember that there was text
                                            xmlWriter.ContainsText = true;
                                        }
                                    }
                                }
                            }

                            // Flag that indicates if we want to preserve whitespace in the front of the text
                            bool frontWhitespace = true;

                            if ((previousTag.isBeginTag) && (previousTag.tagInfo.PreserveContent))
                            {
                                // If the previous tag is a begin tag and we're preserving the content as-is, just write out the text
                                writer.Write(text);
                            }
                            else
                            {
                                if (whiteSpaceType == WhiteSpaceType.NotSignificant)
                                {
                                    // If the whitespace is not significant in this location
                                    if (!inline && !firstOrLastUnknownXmlText)
                                    {
                                        // If the previous tag is not an inline tag, write out a new line
                                        writer.WriteLineIfNotOnNewLine();
                                        // Since we've written out a newline, we no longer need to preserve front whitespace
                                        frontWhitespace = false;
                                    }
                                }
                                else if (whiteSpaceType == WhiteSpaceType.Significant)
                                {
                                    // If the whitespace in this location is significant
                                    if (FormattedTextWriter.HasFrontWhiteSpace(text))
                                    {
                                        // If there is whitespace in the front, that means we can insert more whitespace without
                                        // changing rendering behavior
                                        if (!inline && !firstOrLastUnknownXmlText)
                                        {
                                            // Only insert a new line if the tag isn't inline
                                            writer.WriteLineIfNotOnNewLine();
                                            frontWhitespace = false;
                                        }
                                    }
                                }
                                else if (whiteSpaceType == WhiteSpaceType.CarryThrough)
                                {
                                    // If the whitespace in this location is carry through (meaning whitespace at the end of the previous
                                    // text block eats up any whitespace in this location
                                    if ((sawWhiteSpace) || (FormattedTextWriter.HasFrontWhiteSpace(text)))
                                    {
                                        // If the last text block ended in whitspace or if there is already whitespace in this location
                                        // we can add a new line
                                        if (!inline && !firstOrLastUnknownXmlText)
                                        {
                                            // Only add it if the previous tag isn't inline
                                            writer.WriteLineIfNotOnNewLine();
                                            frontWhitespace = false;
                                        }
                                    }
                                }

                                if (previousTag.isBeginTag)
                                {
                                    // If the previous tag is a begin tag
                                    if (!previousTag.tagInfo.NoIndent && !inline)
                                    {
                                        // Indent if desired
                                        writer.Indent++;
                                    }
                                }

                                // Special case for unknown XML tags:
                                if (firstOrLastUnknownXmlText)
                                {
                                    writer.Write(text);
                                }
                                else
                                {
                                    writer.WriteLiteral(text, frontWhitespace);
                                }
                            }

                            if (currentTag.isEndTag)
                            {
                                // If the currentTag is an end tag
                                if (!currentTag.tagInfo.NoEndTag)
                                {
                                    // Figure out where the corresponding begin tag is
                                    ArrayList popped = new ArrayList();
                                    FormatInfo formatInfo = null;

                                    bool foundOpenTag = false;

                                    bool allowPartial = false;
                                    if ((currentTag.tagInfo.Flags & FormattingFlags.AllowPartialTags) != 0)
                                    {
                                        // Once we've exited a tag that allows partial tags, clear the flag
                                        allowPartial = true;
                                    }

                                    // Start popping off the tag stack if there are tags on the stack
                                    if (tagStack.Count > 0)
                                    {
                                        // Keep popping until we find the right tag, remember what we've popped off
                                        formatInfo = (FormatInfo)tagStack.Pop();
                                        popped.Add(formatInfo);
                                        while ((tagStack.Count > 0) && (formatInfo.tagInfo.TagName.ToLower() != currentTag.tagInfo.TagName.ToLower()))
                                        {
                                            if ((formatInfo.tagInfo.Flags & FormattingFlags.AllowPartialTags) != 0)
                                            {
                                                // Special case for tags that allow partial tags inside of them.
                                                allowPartial = true;
                                                break;
                                            }
                                            formatInfo = (FormatInfo)tagStack.Pop();
                                            popped.Add(formatInfo);
                                        }

                                        if (formatInfo.tagInfo.TagName.ToLower() != currentTag.tagInfo.TagName.ToLower())
                                        {
                                            // If we didn't find the corresponding open tag, push everything back on
                                            for (int i = popped.Count - 1; i >= 0; i--)
                                            {
                                                tagStack.Push(popped[i]);
                                            }
                                        }
                                        else
                                        {
                                            foundOpenTag = true;
                                            for (int i = 0; i < popped.Count - 1; i++)
                                            {
                                                FormatInfo fInfo = (FormatInfo)popped[i];
                                                if (fInfo.tagInfo.IsXml)
                                                {
                                                    // If we have an xml tag that was unclosed, we need to clean up the xml stack
                                                    if (writerStack.Count > 1)
                                                    {
                                                        HtmlWriter oldWriter = (HtmlWriter)writerStack.Pop();
                                                        writer = (HtmlWriter)writerStack.Peek();
                                                        // Write out the contents of the old writer
                                                        writer.Write(oldWriter.Content);
                                                    }
                                                }

                                                if (!fInfo.tagInfo.NoEndTag)
                                                {
                                                    writer.WriteLineIfNotOnNewLine();
                                                    writer.Indent = fInfo.indent;
                                                    if ((makeXhtml) && (!allowPartial))
                                                    {
                                                        // If we're trying to be XHTML compliant, close unclosed child tags
                                                        // Don't close if we are under a tag that allows partial tags
                                                        writer.Write("</"+fInfo.tagInfo.TagName+">");
                                                    }
                                                }
                                            }

                                            // Set the indent to the indent of the corresponding open tag
                                            writer.Indent = formatInfo.indent;
                                        }
                                    }
                                    if (foundOpenTag || allowPartial)
                                    {
                                        // Only write out the close tag if there was a corresponding open tag or we are under
                                        // a tag that allows partial tags
                                        if ((!emptyXml) &&
                                            (!firstOrLastUnknownXmlText) &&
                                            (!currentTag.tagInfo.IsInline) &&
                                            (!currentTag.tagInfo.PreserveContent) &&
                                            (  FormattedTextWriter.IsWhiteSpace(text) ||
                                            FormattedTextWriter.HasBackWhiteSpace(text) ||
                                            (currentTag.tagInfo.FollowingWhiteSpaceType == WhiteSpaceType.NotSignificant)
                                            ) &&
                                            (  !(currentTag.tagInfo is TDTagInfo) ||
                                            FormattedTextWriter.HasBackWhiteSpace(text)
                                            )
                                            )
                                        {
                                            // Insert a newline before the next tag, if allowed
                                            writer.WriteLineIfNotOnNewLine();
                                        }
                                        // Write out the end tag prefix
                                        writer.Write("</");
                                        // Finally, write out the tag name
                                        writer.Write(tagName);
                                    }
                                    else
                                    {
                                        ignoredLastTag = true;
                                    }

                                    if (currentTag.tagInfo.IsXml)
                                    {
                                        // If we have an xml tag that was unclosed, we need to clean up the xml stack
                                        if (writerStack.Count > 1)
                                        {
                                            HtmlWriter oldWriter = (HtmlWriter)writerStack.Pop();
                                            writer = (HtmlWriter)writerStack.Peek();
                                            // Write out the contents of the old writer
                                            writer.Write(oldWriter.Content);
                                        }
                                    }
                                }
                                else
                                {
                                    ignoredLastTag = true;
                                }
                            }
                            else
                            {
                                // If the currentTag is a begin tag
                                bool done = false;
                                // Close implicitClosure tags
                                while (!done && (tagStack.Count > 0))
                                {
                                    // Peek at the top of the stack to see the last unclosed tag
                                    FormatInfo fInfo = (FormatInfo)tagStack.Peek();
                                    // If the currentTag can't be a child of that tag, then we need to close that tag
                                    done = fInfo.tagInfo.CanContainTag(currentTag.tagInfo);
                                    if (!done)
                                    {
                                        // Pop it off and write a close tag for it
                                        // REVIEW: Will XML tags always be able to contained in any tag?  If not we should be cleaning up the writerStack as well...
                                        tagStack.Pop();
                                        writer.Indent = fInfo.indent;
                                        // If we're trying to be XHTML compliant, write in the end tags
                                        if (makeXhtml)
                                        {
                                            if (!fInfo.tagInfo.IsInline)
                                            {
                                                // Only insert a newline if we are allowed to
                                                writer.WriteLineIfNotOnNewLine();
                                            }
                                            writer.Write("</"+fInfo.tagInfo.TagName+">");
                                        }
                                    }
                                }

                                // Remember the indent so we can properly indent the corresponding close tag for this open tag
                                currentTag.indent = writer.Indent;

                                if ((!firstOrLastUnknownXmlText) &&
                                    (!currentTag.tagInfo.IsInline) &&
                                    (!currentTag.tagInfo.PreserveContent) &&
                                    ( (FormattedTextWriter.IsWhiteSpace(text) || FormattedTextWriter.HasBackWhiteSpace(text)) ||
                                    (  (text.Length == 0) &&
                                    (  ((previousTag.isBeginTag) && (previousTag.tagInfo.InnerWhiteSpaceType == WhiteSpaceType.NotSignificant)) ||
                                    ((previousTag.isEndTag) && (previousTag.tagInfo.FollowingWhiteSpaceType == WhiteSpaceType.NotSignificant))
                                    )
                                    )
                                    )
                                    )
                                {
                                    // Insert a newline before the currentTag if we are allowed to
                                    writer.WriteLineIfNotOnNewLine();
                                }

                                if (!currentTag.tagInfo.NoEndTag)
                                {
                                    // Only push tags with close tags onto the stack
                                    tagStack.Push(currentTag);
                                }
                                else
                                {
                                    // If this tag doesn't have a close tag, remember that it is self terminating
                                    sawSelfTerminatingTag = true;
                                }

                                if (currentTag.tagInfo.IsXml)
                                {
                                    // When we encounter an xml block, create a new writer to contain the inner content of the xml
                                    HtmlWriter newWriter = new XmlWriter(writer.Indent, currentTag.tagInfo.TagName, indentString, maxLineLength);
                                    writerStack.Push(newWriter);
                                    writer = newWriter;
                                }

                                writer.Write('<');
                                // Finally, write out the tag name
                                writer.Write(tagName);
                            }

                            // Remember if the text ended in whitespace
                            sawWhiteSpace = FormattedTextWriter.HasBackWhiteSpace(text);

                            // Clear out the text, since we have already outputted it
                            text = String.Empty;

                            previousTag = currentTag;
                        }
                        break;
                    case Token.ServerScriptBlock:
                    case Token.ClientScriptBlock:
                    case Token.Style:
                    case Token.TextToken:
                        // Remember all these types of tokens as text so we can output them between the tags
                        if (makeXhtml)
                        {
                            // UNDONE: Need to implement this in the tokenizer, etc...
                            text += t.Text.Replace("&nbsp;", "&#160;");
                        }
                        else
                        {
                            text += t.Text;
                        }
                        break;
                    case Token.Whitespace:
                        if (t.Text.Length > 0)
                        {
                            writer.Write(' ');
                        }
                        break;
                    default:
                        Debug.Fail("Invalid token type!");
                        break;
                }
                // Remember what the last token was
                lastToken = t;

                // Get the next token
                t = HtmlTokenizer.GetNextToken(t);
            }

            if (text.Length > 0)
            {
                // Write out the last text if there is any
                writer.Write(text);
            }

            while (writerStack.Count > 1)
            {
                // If we haven't cleared out the writer stack, do it
                HtmlWriter oldWriter = (HtmlWriter)writerStack.Pop();
                writer = (HtmlWriter)writerStack.Peek();
                writer.Write(oldWriter.Content);
            }

            // Flush the writer original
            writer.Flush();
        }
Example #5
0
		public virtual bool CanContainTag(TagInfo info) 
		{
			return true;
		}