Exemple #1
0
        /* Function: GetBodyLinks
         * Goes through the body of the passed <Topic> and adds any Natural Docs and image links it finds in the <NDMarkup>
         * to <LinkSet> and <ImageLinkSet>.
         */
        protected void GetBodyLinks(Topic topic, ref LinkSet linkSet, ref ImageLinkSet imageLinkSet)
        {
            if (topic.Body == null)
            {
                return;
            }

            NDMarkup.Iterator iterator = new NDMarkup.Iterator(topic.Body);

            // Doing two passes of GoToFirstTag is probably faster than iterating through each element

            if (iterator.GoToFirstTag("<link type=\"naturaldocs\""))
            {
                do
                {
                    Link link = new Link();

                    // ignore LinkID
                    link.Type    = LinkType.NaturalDocs;
                    link.Text    = iterator.Property("originaltext");
                    link.Context = topic.BodyContext;
                    // ignore contextID
                    link.FileID      = topic.FileID;
                    link.ClassString = topic.ClassString;
                    // ignore classID
                    link.LanguageID = topic.LanguageID;
                    // ignore EndingSymbol
                    // ignore TargetTopicID
                    // ignore TargetScore

                    linkSet.Add(link);
                }while (iterator.GoToNextTag("<link type=\"naturaldocs\""));
            }

            iterator = new NDMarkup.Iterator(topic.Body);

            if (iterator.GoToFirstTag("<image"))
            {
                do
                {
                    ImageLink imageLink = new ImageLink();

                    // ignore ImageLinkID
                    imageLink.OriginalText = iterator.Property("originaltext");
                    imageLink.Path         = new Path(iterator.Property("target"));
                    // ignore FileName, generated from Path
                    imageLink.FileID      = topic.FileID;
                    imageLink.ClassString = topic.ClassString;
                    // ignore classID
                    // ignore TargetFileID
                    // ignore TargetScore

                    imageLinkSet.Add(imageLink);
                }while (iterator.GoToNextTag("<image"));
            }
        }
Exemple #2
0
        /* Function: AppendSummary
         */
        protected void AppendSummary(StringBuilder output)
        {
            output.Append("<div class=\"TTSummary\">");

            string summary = context.Topic.Summary;

            NDMarkup.Iterator iterator = new NDMarkup.Iterator(summary);

            while (iterator.IsInBounds)
            {
                switch (iterator.Type)
                {
                case NDMarkup.Iterator.ElementType.Text:
                    // Preserve multiple whitespace chars, but skip the extra processing if there aren't any
                    if (summary.IndexOf("  ", iterator.RawTextIndex, iterator.Length) != -1)
                    {
                        output.Append(iterator.String.ConvertMultipleWhitespaceChars());
                    }
                    else
                    {
                        iterator.AppendTo(output);
                    }
                    break;

                case NDMarkup.Iterator.ElementType.BoldTag:
                case NDMarkup.Iterator.ElementType.ItalicsTag:
                case NDMarkup.Iterator.ElementType.UnderlineTag:
                case NDMarkup.Iterator.ElementType.LTEntityChar:
                case NDMarkup.Iterator.ElementType.GTEntityChar:
                case NDMarkup.Iterator.ElementType.AmpEntityChar:
                case NDMarkup.Iterator.ElementType.QuoteEntityChar:
                    // These the NDMarkup directly matches the HTML tags
                    iterator.AppendTo(output);
                    break;

                case NDMarkup.Iterator.ElementType.LinkTag:
                    string linkType = iterator.Property("type");

                    if (linkType == "email")
                    {
                        AppendEMailLink(iterator, output);
                    }
                    else if (linkType == "url")
                    {
                        AppendURLLink(iterator, output);
                    }
                    else                             // type == "naturaldocs"
                    {
                        AppendNaturalDocsLink(iterator, output);
                    }

                    break;
                }

                iterator.Next();
            }

            output.Append("</div>");
        }
Exemple #3
0
        /* Function: BuildSummary
         */
        protected void BuildSummary()
        {
            htmlOutput.Append("<div class=\"TTSummary\">");

            NDMarkup.Iterator iterator = new NDMarkup.Iterator(topic.Summary);

            while (iterator.IsInBounds)
            {
                switch (iterator.Type)
                {
                case NDMarkup.Iterator.ElementType.Text:
                    if (topic.Body.IndexOf("  ", iterator.RawTextIndex, iterator.Length) == -1)
                    {
                        iterator.AppendTo(htmlOutput);
                    }
                    else
                    {
                        htmlOutput.Append(iterator.String.ConvertMultipleWhitespaceChars());
                    }
                    break;

                case NDMarkup.Iterator.ElementType.BoldTag:
                case NDMarkup.Iterator.ElementType.ItalicsTag:
                case NDMarkup.Iterator.ElementType.UnderlineTag:
                case NDMarkup.Iterator.ElementType.LTEntityChar:
                case NDMarkup.Iterator.ElementType.GTEntityChar:
                case NDMarkup.Iterator.ElementType.AmpEntityChar:
                case NDMarkup.Iterator.ElementType.QuoteEntityChar:
                    iterator.AppendTo(htmlOutput);
                    break;

                case NDMarkup.Iterator.ElementType.LinkTag:
                    string linkType = iterator.Property("type");

                    if (linkType == "email")
                    {
                        BuildEMailLink(iterator);
                    }
                    else if (linkType == "url")
                    {
                        BuildURLLink(iterator);
                    }
                    else                             // type == "naturaldocs"
                    {
                        BuildNaturalDocsLink(iterator);
                    }

                    break;
                }

                iterator.Next();
            }

            htmlOutput.Append("</div>");
        }
Exemple #4
0
        /* Function: AppendInlineImageLink
         */
        protected void AppendInlineImageLink(NDMarkup.Iterator iterator, StringBuilder output)
        {
            // Create a link object with the identifying properties needed to look it up in the list of links.

            ImageLink imageLinkStub = new ImageLink();

            imageLinkStub.OriginalText = iterator.Property("originaltext");
            imageLinkStub.FileID       = context.Topic.FileID;
            imageLinkStub.ClassString  = context.Topic.ClassString;
            imageLinkStub.ClassID      = context.Topic.ClassID;


            // Find the actual link so we know if it resolved to anything.

            ImageLink fullImageLink = null;

            foreach (var imageLink in imageLinks)
            {
                if (imageLink.SameIdentifyingPropertiesAs(imageLinkStub))
                {
                    fullImageLink = imageLink;
                    break;
                }
            }

                        #if DEBUG
            if (fullImageLink == null)
            {
                throw new Exception("All image links in a topic must be in the list passed to HTMLTooltip.");
            }
                        #endif


            if (fullImageLink.IsResolved)
            {
                output.EntityEncodeAndAppend(iterator.Property("linktext"));
            }
            else
            {
                output.EntityEncodeAndAppend(iterator.Property("originaltext"));
            }
        }
Exemple #5
0
        /* Function: BuildEMailLink
         */
        protected void BuildEMailLink(NDMarkup.Iterator iterator)
        {
            string address   = iterator.Property("target");
            int    atIndex   = address.IndexOf('@');
            int    cutPoint1 = atIndex / 2;
            int    cutPoint2 = (atIndex + 1) + ((address.Length - (atIndex + 1)) / 2);

            if (!isToolTip)
            {
                htmlOutput.Append("<a href=\"#\" onclick=\"javascript:location.href='ma\\u0069'+'lto\\u003a'+'");
                htmlOutput.Append(EMailSegmentForJavaScriptString(address.Substring(0, cutPoint1)));
                htmlOutput.Append("'+'");
                htmlOutput.Append(EMailSegmentForJavaScriptString(address.Substring(cutPoint1, atIndex - cutPoint1)));
                htmlOutput.Append("'+'\\u0040'+'");
                htmlOutput.Append(EMailSegmentForJavaScriptString(address.Substring(atIndex + 1, cutPoint2 - (atIndex + 1))));
                htmlOutput.Append("'+'");
                htmlOutput.Append(EMailSegmentForJavaScriptString(address.Substring(cutPoint2, address.Length - cutPoint2)));
                htmlOutput.Append("';return false;\">");
            }

            string text = iterator.Property("text");

            if (text != null)
            {
                htmlOutput.EntityEncodeAndAppend(text);
            }
            else
            {
                htmlOutput.Append(EMailSegmentForHTML(address.Substring(0, cutPoint1)));
                htmlOutput.Append("<span style=\"display: none\">[xxx]</span>");
                htmlOutput.Append(EMailSegmentForHTML(address.Substring(cutPoint1, atIndex - cutPoint1)));
                htmlOutput.Append("<span>&#64;</span>");
                htmlOutput.Append(EMailSegmentForHTML(address.Substring(atIndex + 1, cutPoint2 - (atIndex + 1))));
                htmlOutput.Append("<span style=\"display: none\">[xxx]</span>");
                htmlOutput.Append(EMailSegmentForHTML(address.Substring(cutPoint2, address.Length - cutPoint2)));
            }

            if (!isToolTip)
            {
                htmlOutput.Append("</a>");
            }
        }
Exemple #6
0
        /* Function: AppendEMailLink
         */
        protected void AppendEMailLink(NDMarkup.Iterator iterator, StringBuilder output)
        {
            string text = iterator.Property("text");

            if (text != null)
            {
                output.EntityEncodeAndAppend(text);
            }
            else
            {
                string address   = iterator.Property("target");
                int    atIndex   = address.IndexOf('@');
                int    cutPoint1 = atIndex / 2;
                int    cutPoint2 = (atIndex + 1) + ((address.Length - (atIndex + 1)) / 2);

                output.Append(EMailSegmentForHTML(address.Substring(0, cutPoint1)));
                output.Append("<span style=\"display: none\">[xxx]</span>");
                output.Append(EMailSegmentForHTML(address.Substring(cutPoint1, atIndex - cutPoint1)));
                output.Append("<span>&#64;</span>");
                output.Append(EMailSegmentForHTML(address.Substring(atIndex + 1, cutPoint2 - (atIndex + 1))));
                output.Append("<span style=\"display: none\">[xxx]</span>");
                output.Append(EMailSegmentForHTML(address.Substring(cutPoint2, address.Length - cutPoint2)));
            }
        }
Exemple #7
0
        /* Function: AppendNaturalDocsLink
         */
        protected void AppendNaturalDocsLink(NDMarkup.Iterator iterator, StringBuilder output)
        {
            // Create a link object with the identifying properties needed to look it up in the list of links.

            Link linkStub = new Link();

            linkStub.Type        = LinkType.NaturalDocs;
            linkStub.Text        = iterator.Property("originaltext");
            linkStub.Context     = context.Topic.BodyContext;
            linkStub.ContextID   = context.Topic.BodyContextID;
            linkStub.FileID      = context.Topic.FileID;
            linkStub.ClassString = context.Topic.ClassString;
            linkStub.ClassID     = context.Topic.ClassID;
            linkStub.LanguageID  = context.Topic.LanguageID;


            // Find the actual link so we know if it resolved to anything.

            Link fullLink = null;

            foreach (Link link in links)
            {
                if (link.SameIdentifyingPropertiesAs(linkStub))
                {
                    fullLink = link;
                    break;
                }
            }

                        #if DEBUG
            if (fullLink == null)
            {
                throw new Exception("All links in a topic must be in the list passed to Tooltip.");
            }
                        #endif


            // If it didn't resolve, we just output the original text and we're done.

            if (!fullLink.IsResolved)
            {
                output.EntityEncodeAndAppend(iterator.Property("originaltext"));
                return;
            }


            // If it did resolve, find the interpretation that was used.  If it was a named link it would affect the link text.

            LinkInterpretation linkInterpretation = null;

            string ignore;
            List <LinkInterpretation> linkInterpretations = EngineInstance.Comments.NaturalDocsParser.LinkInterpretations(fullLink.Text,
                                                                                                                          Comments.Parsers.NaturalDocs.LinkInterpretationFlags.AllowNamedLinks |
                                                                                                                          Comments.Parsers.NaturalDocs.LinkInterpretationFlags.AllowPluralsAndPossessives |
                                                                                                                          Comments.Parsers.NaturalDocs.LinkInterpretationFlags.FromOriginalText,
                                                                                                                          out ignore);

            linkInterpretation = linkInterpretations[fullLink.TargetInterpretationIndex];


            // Since it's a tooltip, that's all we need.  We don't need to find the Topic because we're not creating an actual link;
            // you can't click on tooltips.  We just needed to know what the text should be.

            output.EntityEncodeAndAppend(linkInterpretation.Text);
        }
Exemple #8
0
        /* Function: AppendURLLink
         */
        protected void AppendURLLink(NDMarkup.Iterator iterator, StringBuilder output)
        {
            string text = iterator.Property("text");

            if (text != null)
            {
                output.EntityEncodeAndAppend(text);
            }
            else
            {
                string target = iterator.Property("target");

                int startIndex = 0;
                int breakIndex;

                // Skip the protocol and any following slashes since we don't want a break after every slash in http:// or
                // file:///.

                int endOfProtocolIndex = target.IndexOf(':');

                if (endOfProtocolIndex != -1)
                {
                    do
                    {
                        endOfProtocolIndex++;
                    }while (endOfProtocolIndex < target.Length && target[endOfProtocolIndex] == '/');

                    output.EntityEncodeAndAppend(target.Substring(0, endOfProtocolIndex));
                    output.Append("&#8203;");                      // Zero width space
                    startIndex = endOfProtocolIndex;
                }

                for (;;)
                {
                    breakIndex = target.IndexOfAny(BreakURLCharacters, startIndex);

                    if (breakIndex == -1)
                    {
                        if (target.Length - startIndex > MaxUnbrokenURLCharacters)
                        {
                            breakIndex = startIndex + MaxUnbrokenURLCharacters;
                        }
                        else
                        {
                            break;
                        }
                    }
                    else if (breakIndex - startIndex > MaxUnbrokenURLCharacters)
                    {
                        breakIndex = startIndex + MaxUnbrokenURLCharacters;
                    }

                    output.EntityEncodeAndAppend(target.Substring(startIndex, breakIndex - startIndex));
                    output.Append("&#8203;");                      // Zero width space
                    output.EntityEncodeAndAppend(target[breakIndex]);

                    startIndex = breakIndex + 1;
                }

                output.EntityEncodeAndAppend(target.Substring(startIndex));
            }
        }
Exemple #9
0
        /* Function: MakeSummaryFromBody
         * If the <Topic> has a body, attempts to extract a summary from it and set <Topic.Summary>.
         */
        public bool MakeSummaryFromBody(Topic topic)
        {
            if (topic.Body == null)
            {
                return(false);
            }

            NDMarkup.Iterator iterator = new NDMarkup.Iterator(topic.Body);

            while (iterator.IsInBounds)
            {
                // Allow headings to come before the opening paragraph.
                // We can assume the NDMarkup is valid, so we can assume this is an opening tag and we'll hit a closing tag.
                if (iterator.Type == NDMarkup.Iterator.ElementType.HeadingTag)
                {
                    do
                    {
                        iterator.Next();
                    }while (iterator.Type != NDMarkup.Iterator.ElementType.HeadingTag);

                    iterator.Next();
                }

                // Also allow prototypes to come before the opening paragraph.
                else if (iterator.Type == NDMarkup.Iterator.ElementType.PreTag && iterator.Property("type") == "prototype")
                {
                    do
                    {
                        iterator.Next();
                    }while (iterator.Type != NDMarkup.Iterator.ElementType.PreTag);

                    iterator.Next();
                }

                // Extract the entire openng paragraph for the summary, unlike Natural Docs 1.x which only used the first sentence.
                else if (iterator.Type == NDMarkup.Iterator.ElementType.ParagraphTag)
                {
                    // Don't include the opening <p> in the summary.
                    iterator.Next();

                    int startingIndex = iterator.RawTextIndex;

                    while (iterator.Type != NDMarkup.Iterator.ElementType.ParagraphTag)
                    {
                        iterator.Next();
                    }

                    // Iterator is now on the closing </p>.

                    topic.Summary = topic.Body.Substring(startingIndex, iterator.RawTextIndex - startingIndex);
                    return(true);
                }

                // If we hit any other tag before a paragraph, there is no summary.
                else
                {
                    break;
                }
            }

            return(false);
        }
Exemple #10
0
        /* Function: AppendInlineImageLink
         */
        protected void AppendInlineImageLink(NDMarkup.Iterator iterator, StringBuilder linkOutput, StringBuilder imageOutput, int imageNumber)
        {
            // Create a link object with the identifying properties needed to look it up in the list of links.

            ImageLink imageLinkStub = new ImageLink();

            imageLinkStub.OriginalText = iterator.Property("originaltext");
            imageLinkStub.FileID       = context.Topic.FileID;
            imageLinkStub.ClassString  = context.Topic.ClassString;
            imageLinkStub.ClassID      = context.Topic.ClassID;


            // Find the actual link so we know if it resolved to anything.

            ImageLink fullImageLink = null;

            foreach (var imageLink in imageLinks)
            {
                if (imageLink.SameIdentifyingPropertiesAs(imageLinkStub))
                {
                    fullImageLink = imageLink;
                    break;
                }
            }

                        #if DEBUG
            if (fullImageLink == null)
            {
                throw new Exception("All image links in a topic must be in the list passed to HTMLTopic.");
            }
                        #endif


            // If it didn't resolve, we just output the original text and we're done.

            if (!fullImageLink.IsResolved)
            {
                linkOutput.EntityEncodeAndAppend(iterator.Property("originaltext"));
                return;
            }


            Files.ImageFile targetFile  = (Files.ImageFile)EngineInstance.Files.FromID(fullImageLink.TargetFileID);
            string          description = targetFile.FileName.NameWithoutPathOrExtension;
            string          anchor      = "Topic" + context.Topic.TopicID + "_Image" + imageNumber;

            var  fileSource               = EngineInstance.Files.FileSourceOf(targetFile);
            Path relativeTargetPath       = fileSource.MakeRelative(targetFile.FileName);
            Path targetOutputPath         = Paths.Image.OutputFile(context.Target.OutputFolder, fileSource.Number, fileSource.Type, relativeTargetPath);
            Path relativeTargetOutputPath = targetOutputPath.MakeRelativeTo(context.OutputFile.ParentFolder);

            linkOutput.Append(
                "<a href=\"#" + anchor + "\" class=\"SeeImageLink\">" +
                iterator.Property("linktext").EntityEncode() +
                "</a>");

            imageOutput.Append(
                "<div class=\"CImage\">" +

                "<a name=\"" + anchor + "\"></a>" +

                "<a href=\"" + relativeTargetOutputPath.ToURL().EntityEncode() + "\" target=\"_blank\" class=\"ZoomLink\">" +

                "<img src=\"" + relativeTargetOutputPath.ToURL().EntityEncode() + "\" loading=\"lazy\" " +
                (targetFile.DimensionsKnown ?
                 "class=\"KnownDimensions\" width=\"" + targetFile.Width + "\" height=\"" + targetFile.Height + "\" " +
                 "style=\"max-width: " + targetFile.Width + "px\" " :
                 "class=\"UnknownDimensions\" ") +
                "alt=\"" + description.EntityEncode() + "\" />" +

                "</a>" +

                "<div class=\"CICaption\">" +
                description.EntityEncode() +
                "</div>" +

                "</div>");
        }
Exemple #11
0
        /* Function: AppendBody
         */
        protected void AppendBody(StringBuilder output)
        {
            output.Append("<div class=\"CBody\">");

            string body = context.Topic.Body;

            NDMarkup.Iterator iterator = new NDMarkup.Iterator(body);

            bool   underParameterHeading  = false;
            string parameterListSymbol    = null;
            string altParameterListSymbol = null;

            StringBuilder inlineImageContent = null;
            int           imageNumber        = 1;

            while (iterator.IsInBounds)
            {
                switch (iterator.Type)
                {
                case NDMarkup.Iterator.ElementType.Text:

                    // Preserve multiple whitespace chars, but skip the extra processing if there aren't any
                    if (body.IndexOf("  ", iterator.RawTextIndex, iterator.Length) != -1)
                    {
                        output.Append(iterator.String.ConvertMultipleWhitespaceChars());
                    }
                    else
                    {
                        iterator.AppendTo(output);
                    }
                    break;


                case NDMarkup.Iterator.ElementType.ParagraphTag:

                    iterator.AppendTo(output);

                    if (iterator.IsClosingTag && inlineImageContent != null && inlineImageContent.Length > 0)
                    {
                        output.Append(inlineImageContent.ToString());
                        inlineImageContent.Remove(0, inlineImageContent.Length);
                    }

                    break;


                case NDMarkup.Iterator.ElementType.BulletListTag:
                case NDMarkup.Iterator.ElementType.BulletListItemTag:
                case NDMarkup.Iterator.ElementType.BoldTag:
                case NDMarkup.Iterator.ElementType.ItalicsTag:
                case NDMarkup.Iterator.ElementType.UnderlineTag:
                case NDMarkup.Iterator.ElementType.LTEntityChar:
                case NDMarkup.Iterator.ElementType.GTEntityChar:
                case NDMarkup.Iterator.ElementType.AmpEntityChar:
                case NDMarkup.Iterator.ElementType.QuoteEntityChar:

                    // These the NDMarkup directly matches the HTML tags
                    iterator.AppendTo(output);
                    break;


                case NDMarkup.Iterator.ElementType.HeadingTag:

                    if (iterator.IsOpeningTag)
                    {
                        output.Append("<div class=\"CHeading\">");
                        underParameterHeading = (iterator.Property("type") == "parameters");
                    }
                    else
                    {
                        output.Append("</div>");
                    }
                    break;


                case NDMarkup.Iterator.ElementType.PreTag:

                    string preType         = iterator.Property("type");
                    string preLanguageName = iterator.Property("language");

                    iterator.Next();
                    NDMarkup.Iterator startOfCode = iterator;

                    // Because we can assume the NDMarkup is valid, we can assume we were on an opening tag and that we will
                    // run into a closing tag before the end of the text.  We can also assume the next pre tag is a closing tag.

                    while (iterator.Type != NDMarkup.Iterator.ElementType.PreTag)
                    {
                        iterator.Next();
                    }

                    string ndMarkupCode = body.Substring(startOfCode.RawTextIndex, iterator.RawTextIndex - startOfCode.RawTextIndex);
                    string textCode     = NDMarkupCodeToText(ndMarkupCode);

                    output.Append("<pre>");

                    if (preType == "code")
                    {
                        Languages.Language preLanguage = null;

                        if (preLanguageName != null)
                        {
                            // This can return null if the language name is unrecognized.
                            preLanguage = EngineInstance.Languages.FromName(preLanguageName);
                        }

                        if (preLanguage == null)
                        {
                            preLanguage = EngineInstance.Languages.FromID(context.Topic.LanguageID);
                        }

                        Tokenizer code = new Tokenizer(textCode, tabWidth: EngineInstance.Config.TabWidth);
                        preLanguage.Parser.SyntaxHighlight(code);
                        AppendSyntaxHighlightedText(code.FirstToken, code.LastToken, output);
                    }
                    else
                    {
                        string htmlCode = textCode.EntityEncode();
                        htmlCode = StringExtensions.LineBreakRegex.Replace(htmlCode, "<br />");
                        output.Append(htmlCode);
                    }

                    output.Append("</pre>");
                    break;


                case NDMarkup.Iterator.ElementType.DefinitionListTag:

                    if (iterator.IsOpeningTag)
                    {
                        output.Append("<table class=\"CDefinitionList\">");
                    }
                    else
                    {
                        output.Append("</table>");
                    }
                    break;


                case NDMarkup.Iterator.ElementType.DefinitionListEntryTag:
                case NDMarkup.Iterator.ElementType.DefinitionListSymbolTag:

                    if (iterator.IsOpeningTag)
                    {
                        output.Append("<tr><td class=\"CDLEntry\">");
                        parameterListSymbol = null;

                        // Create anchors for symbols.  We are assuming there are enough embedded topics for each <ds>
                        // tag and that they follow their parent topic in order.
                        if (iterator.Type == NDMarkup.Iterator.ElementType.DefinitionListSymbolTag)
                        {
                                                                #if DEBUG
                            if (embeddedTopics == null || embeddedTopicIndex >= embeddedTopics.Count ||
                                embeddedTopics[embeddedTopicIndex].IsEmbedded == false)
                            {
                                throw new Exception("There are not enough embedded topics to build the definition list.");
                            }
                                                                #endif

                            var embeddedTopic = embeddedTopics[embeddedTopicIndex];

                            Context embeddedTopicContext = context;
                            embeddedTopicContext.Topic = embeddedTopic;

                            string embeddedTopicHashPath = embeddedTopicContext.TopicOnlyHashPath;

                            if (embeddedTopicHashPath != null)
                            {
                                output.Append("<a name=\"" + embeddedTopicHashPath.EntityEncode() + "\"></a>");
                            }

                            output.Append("<a name=\"Topic" + embeddedTopic.TopicID + "\"></a>");

                            embeddedTopicIndex++;
                        }

                        // If we're using a Parameters: heading, store the entry symbol in parameterListSymbol
                        if (underParameterHeading)
                        {
                            NDMarkup.Iterator temp = iterator;
                            temp.Next();

                            StringBuilder symbol = new StringBuilder();

                            while (temp.IsInBounds &&
                                   temp.Type != NDMarkup.Iterator.ElementType.DefinitionListEntryTag &&
                                   temp.Type != NDMarkup.Iterator.ElementType.DefinitionListSymbolTag)
                            {
                                if (temp.Type == NDMarkup.Iterator.ElementType.Text)
                                {
                                    temp.AppendTo(symbol);
                                }

                                temp.Next();
                            }

                            // If the entry name starts with any combination of $, @, or % characters, strip them off.
                            int firstNonSymbolIndex = 0;
                            while (firstNonSymbolIndex < symbol.Length)
                            {
                                char charAtIndex = symbol[firstNonSymbolIndex];

                                if (charAtIndex != '$' && charAtIndex != '@' && charAtIndex != '%')
                                {
                                    break;
                                }

                                firstNonSymbolIndex++;
                            }

                            if (symbol.Length > 0)
                            {
                                parameterListSymbol = symbol.ToString();
                            }
                            else
                            {
                                parameterListSymbol = null;
                            }

                            if (firstNonSymbolIndex > 0)
                            {
                                symbol.Remove(0, firstNonSymbolIndex);
                                altParameterListSymbol = symbol.ToString();
                            }
                            else
                            {
                                altParameterListSymbol = null;
                            }
                        }
                    }
                    else                             // closing tag
                    {
                        // See if parameterListSymbol matches any of the prototype parameter names
                        if ((parameterListSymbol != null || altParameterListSymbol != null) && context.Topic.Prototype != null)
                        {
                            var           parsedPrototype = context.Topic.ParsedPrototype;
                            TokenIterator start, end;
                            int           matchedParameter = -1;

                            for (int i = 0; i < parsedPrototype.NumberOfParameters; i++)
                            {
                                parsedPrototype.GetParameterName(i, out start, out end);

                                if ((parameterListSymbol != null && parsedPrototype.Tokenizer.EqualsTextBetween(parameterListSymbol, true, start, end)) ||
                                    (altParameterListSymbol != null && parsedPrototype.Tokenizer.EqualsTextBetween(altParameterListSymbol, true, start, end)))
                                {
                                    matchedParameter = i;
                                    break;
                                }
                            }

                            // If so, include the type under the entry in the HTML
                            if (matchedParameter != -1)
                            {
                                parsedPrototype.BuildFullParameterType(matchedParameter, out start, out end);

                                if (start < end &&
                                    // Don't include single symbol types
                                    !(end.RawTextIndex - start.RawTextIndex == 1 &&
                                      (start.Character == '$' || start.Character == '@' || start.Character == '%')))
                                {
                                    output.Append("<div class=\"CDLParameterType\">");
                                    AppendSyntaxHighlightedTextWithTypeLinks(start, end, output, links, linkTargets);
                                    output.Append("</div>");
                                }
                            }
                        }

                        output.Append("</td>");
                    }
                    break;


                case NDMarkup.Iterator.ElementType.DefinitionListDefinitionTag:

                    if (iterator.IsOpeningTag)
                    {
                        output.Append("<td class=\"CDLDefinition\">");
                    }
                    else
                    {
                        output.Append("</td></tr>");
                    }
                    break;


                case NDMarkup.Iterator.ElementType.LinkTag:

                    string linkType = iterator.Property("type");

                    if (linkType == "email")
                    {
                        AppendEMailLink(iterator, output);
                    }
                    else if (linkType == "url")
                    {
                        AppendURLLink(iterator, output);
                    }
                    else                             // type == "naturaldocs"
                    {
                        AppendNaturalDocsLink(iterator, output);
                    }

                    break;


                case NDMarkup.Iterator.ElementType.ImageTag:

                    if (iterator.Property("type") == "standalone")
                    {
                        AppendStandaloneImageLink(iterator, output);
                    }

                    else if (iterator.Property("type") == "inline")
                    {
                        if (inlineImageContent == null)
                        {
                            inlineImageContent = new StringBuilder();
                        }

                        AppendInlineImageLink(iterator, output, inlineImageContent, imageNumber);

                        imageNumber++;
                    }

                    else
                    {
                        throw new NotImplementedException();
                    }

                    break;
                }

                iterator.Next();
            }

            output.Append("</div>");
        }
Exemple #12
0
        /* Function: BuildBody
         */
        protected void BuildBody()
        {
            htmlOutput.Append("<div class=\"CBody\">");

            NDMarkup.Iterator iterator = new NDMarkup.Iterator(topic.Body);

            bool   underParameterHeading = false;
            string parameterListSymbol   = null;

            while (iterator.IsInBounds)
            {
                switch (iterator.Type)
                {
                case NDMarkup.Iterator.ElementType.Text:
                    if (topic.Body.IndexOf("  ", iterator.RawTextIndex, iterator.Length) == -1)
                    {
                        iterator.AppendTo(htmlOutput);
                    }
                    else
                    {
                        htmlOutput.Append(iterator.String.ConvertMultipleWhitespaceChars());
                    }
                    break;

                case NDMarkup.Iterator.ElementType.ParagraphTag:
                case NDMarkup.Iterator.ElementType.BulletListTag:
                case NDMarkup.Iterator.ElementType.BulletListItemTag:
                case NDMarkup.Iterator.ElementType.BoldTag:
                case NDMarkup.Iterator.ElementType.ItalicsTag:
                case NDMarkup.Iterator.ElementType.UnderlineTag:
                case NDMarkup.Iterator.ElementType.LTEntityChar:
                case NDMarkup.Iterator.ElementType.GTEntityChar:
                case NDMarkup.Iterator.ElementType.AmpEntityChar:
                case NDMarkup.Iterator.ElementType.QuoteEntityChar:
                    iterator.AppendTo(htmlOutput);
                    break;

                case NDMarkup.Iterator.ElementType.HeadingTag:
                    if (iterator.IsOpeningTag)
                    {
                        htmlOutput.Append("<div class=\"CHeading\">");
                        underParameterHeading = (iterator.Property("type") == "parameters");
                    }
                    else
                    {
                        htmlOutput.Append("</div>");
                    }
                    break;

                case NDMarkup.Iterator.ElementType.PreTag:

                    string preType         = iterator.Property("type");
                    string preLanguageName = iterator.Property("language");

                    iterator.Next();
                    NDMarkup.Iterator startOfCode = iterator;

                    // Because we can assume the NDMarkup is valid, we can assume we were on an opening tag and that we will
                    // run into a closing tag before the end of the text.  We can also assume the next pre tag is a closing tag.

                    while (iterator.Type != NDMarkup.Iterator.ElementType.PreTag)
                    {
                        iterator.Next();
                    }

                    string ndMarkupCode = topic.Body.Substring(startOfCode.RawTextIndex, iterator.RawTextIndex - startOfCode.RawTextIndex);
                    string textCode     = NDMarkupCodeToText(ndMarkupCode);

                    htmlOutput.Append("<pre>");

                    if (preType == "code")
                    {
                        Languages.Language preLanguage = null;

                        if (preLanguageName != null)
                        {
                            // This can return null if the language name is unrecognized.
                            preLanguage = EngineInstance.Languages.FromName(preLanguageName);
                        }

                        if (preLanguage == null)
                        {
                            preLanguage = EngineInstance.Languages.FromID(topic.LanguageID);
                        }

                        Tokenizer code = new Tokenizer(textCode, tabWidth: EngineInstance.Config.TabWidth);
                        preLanguage.SyntaxHighlight(code);
                        BuildSyntaxHighlightedText(code.FirstToken, code.LastToken);
                    }
                    else
                    {
                        string htmlCode = textCode.EntityEncode();
                        htmlCode = StringExtensions.LineBreakRegex.Replace(htmlCode, "<br />");
                        htmlOutput.Append(htmlCode);
                    }

                    htmlOutput.Append("</pre>");
                    break;

                case NDMarkup.Iterator.ElementType.DefinitionListTag:
                    if (iterator.IsOpeningTag)
                    {
                        htmlOutput.Append("<table class=\"CDefinitionList\">");
                    }
                    else
                    {
                        htmlOutput.Append("</table>");
                    }
                    break;

                case NDMarkup.Iterator.ElementType.DefinitionListEntryTag:
                case NDMarkup.Iterator.ElementType.DefinitionListSymbolTag:
                    if (iterator.IsOpeningTag)
                    {
                        htmlOutput.Append("<tr><td class=\"CDLEntry\">");
                        parameterListSymbol = null;

                        // Create anchors for symbols.  We are assuming there are enough embedded topics for each <ds>
                        // tag and that they follow their parent topic in order.
                        if (iterator.Type == NDMarkup.Iterator.ElementType.DefinitionListSymbolTag)
                        {
                                                                #if DEBUG
                            if (embeddedTopics == null || embeddedTopicIndex >= embeddedTopics.Count ||
                                embeddedTopics[embeddedTopicIndex].IsEmbedded == false)
                            {
                                throw new Exception("There are not enough embedded topics to build the definition list.");
                            }
                                                                #endif

                            string topicHashPath = HTMLBuilder.Source_TopicHashPath(embeddedTopics[embeddedTopicIndex], topicPage.IncludeClassInTopicHashPaths);

                            if (topicHashPath != null)
                            {
                                htmlOutput.Append("<a name=\"" + topicHashPath.EntityEncode() + "\"></a>");
                            }

                            htmlOutput.Append("<a name=\"Topic" + embeddedTopics[embeddedTopicIndex].TopicID + "\"></a>");

                            embeddedTopicIndex++;
                        }

                        // If we're using a Parameters: heading, store the entry symbol in parameterListSymbol
                        if (underParameterHeading)
                        {
                            NDMarkup.Iterator temp = iterator;
                            temp.Next();

                            StringBuilder symbol = new StringBuilder();

                            while (temp.IsInBounds &&
                                   temp.Type != NDMarkup.Iterator.ElementType.DefinitionListEntryTag &&
                                   temp.Type != NDMarkup.Iterator.ElementType.DefinitionListSymbolTag)
                            {
                                if (temp.Type == NDMarkup.Iterator.ElementType.Text)
                                {
                                    temp.AppendTo(symbol);
                                }

                                temp.Next();
                            }

                            // If the entry name starts with any combination of $, @, or % characters, strip them off.
                            int firstNonSymbolIndex = 0;
                            while (firstNonSymbolIndex < symbol.Length)
                            {
                                char charAtIndex = symbol[firstNonSymbolIndex];

                                if (charAtIndex != '$' && charAtIndex != '@' && charAtIndex != '%')
                                {
                                    break;
                                }

                                firstNonSymbolIndex++;
                            }

                            if (firstNonSymbolIndex > 0)
                            {
                                symbol.Remove(0, firstNonSymbolIndex);
                            }

                            if (symbol.Length > 0)
                            {
                                parameterListSymbol = symbol.ToString();
                            }
                        }
                    }
                    else                             // closing tag
                    {
                        // See if parameterListSymbol matches any of the prototype parameter names
                        if (parameterListSymbol != null && topic.Prototype != null)
                        {
                            TokenIterator start, end;
                            int           matchedParameter = -1;

                            for (int i = 0; i < topic.ParsedPrototype.NumberOfParameters; i++)
                            {
                                topic.ParsedPrototype.GetParameterName(i, out start, out end);

                                if (topic.ParsedPrototype.Tokenizer.EqualsTextBetween(parameterListSymbol, true, start, end))
                                {
                                    matchedParameter = i;
                                    break;
                                }
                            }

                            // If so, include the type under the entry in the HTML
                            if (matchedParameter != -1)
                            {
                                TokenIterator extraModifierStart, extraModifierEnd, prefixStart, prefixEnd, suffixStart, suffixEnd;
                                topic.ParsedPrototype.GetFullParameterType(matchedParameter, out start, out end,
                                                                           out extraModifierStart, out extraModifierEnd,
                                                                           out prefixStart, out prefixEnd,
                                                                           out suffixStart, out suffixEnd);

                                if (start < end &&
                                    // Don't include single symbol types
                                    (end.RawTextIndex - start.RawTextIndex > 1 ||
                                     (start.Character != '$' && start.Character != '@' && start.Character != '%')))
                                {
                                    htmlOutput.Append("<div class=\"CDLParameterType\">");

                                    if (extraModifierStart < extraModifierEnd)
                                    {
                                        BuildTypeLinkedAndSyntaxHighlightedText(extraModifierStart, extraModifierEnd);
                                        htmlOutput.Append(' ');
                                    }

                                    BuildTypeLinkedAndSyntaxHighlightedText(start, end);
                                    BuildTypeLinkedAndSyntaxHighlightedText(prefixStart, prefixEnd);
                                    BuildTypeLinkedAndSyntaxHighlightedText(suffixStart, suffixEnd);

                                    htmlOutput.Append("</div>");
                                }
                            }
                        }

                        htmlOutput.Append("</td>");
                    }
                    break;

                case NDMarkup.Iterator.ElementType.DefinitionListDefinitionTag:
                    if (iterator.IsOpeningTag)
                    {
                        htmlOutput.Append("<td class=\"CDLDefinition\">");
                    }
                    else
                    {
                        htmlOutput.Append("</td></tr>");
                    }
                    break;

                case NDMarkup.Iterator.ElementType.LinkTag:
                    string linkType = iterator.Property("type");

                    if (linkType == "email")
                    {
                        BuildEMailLink(iterator);
                    }
                    else if (linkType == "url")
                    {
                        BuildURLLink(iterator);
                    }
                    else                             // type == "naturaldocs"
                    {
                        BuildNaturalDocsLink(iterator);
                    }

                    break;

                case NDMarkup.Iterator.ElementType.ImageTag:                         // xxx
                    if (iterator.Property("type") == "standalone")
                    {
                        htmlOutput.Append("<p>");
                    }

                    htmlOutput.Append(iterator.Property("originaltext").ToHTML());

                    if (iterator.Property("type") == "standalone")
                    {
                        htmlOutput.Append("</p>");
                    }
                    break;
                }

                iterator.Next();
            }

            htmlOutput.Append("</div>");
        }