Exemple #1
0
        static Common()
        {
            BoldItalicTextInline.AddTripChars(_triggerList);
            BoldTextInline.AddTripChars(_triggerList);
            ItalicTextInline.AddTripChars(_triggerList);
            MarkdownLinkInline.AddTripChars(_triggerList);
            HyperlinkInline.AddTripChars(_triggerList);
            StrikethroughTextInline.AddTripChars(_triggerList);
            CodeInline.AddTripChars(_triggerList);
            ImageInline.AddTripChars(_triggerList);
            EmojiInline.AddTripChars(_triggerList);
            LinkAnchorInline.AddTripChars(_triggerList);
            DiscordInline.AddTripChars(_triggerList);
            SpoilerTextInline.AddTripChars(_triggerList);

            // Create an array of characters to search against using IndexOfAny.
            _tripCharacters = _triggerList.Select(trigger => trigger.FirstChar).Distinct().ToArray();
        }
Exemple #2
0
        /// <summary>
        /// Finds the next inline element by matching trip chars and verifying the match.
        /// </summary>
        /// <param name="markdown"> The markdown text to parse. </param>
        /// <param name="start"> The position to start parsing. </param>
        /// <param name="end"> The position to stop parsing. </param>
        /// <param name="ignoreLinks"> Indicates whether to parse links. </param>
        /// <returns>Returns the next element</returns>
        private static InlineParseResult FindNextInlineElement(string markdown, int start, int end, bool ignoreLinks)
        {
            // Search for the next inline sequence.
            for (int pos = start; pos < end; pos++)
            {
                // IndexOfAny should be the fastest way to skip characters we don't care about.
                pos = markdown.IndexOfAny(_tripCharacters, pos, end - pos);
                if (pos < 0)
                {
                    break;
                }

                // Find the trigger(s) that matched.
                char currentChar = markdown[pos];
                foreach (InlineTripCharHelper currentTripChar in _triggerList)
                {
                    // Check if our current char matches the suffix char.
                    if (currentChar == currentTripChar.FirstChar)
                    {
                        // Don't match if the previous character was a backslash.
                        if (pos > start && markdown[pos - 1] == '\\')
                        {
                            continue;
                        }

                        // If we are here we have a possible match. Call into the inline class to verify.
                        InlineParseResult parseResult = null;
                        switch (currentTripChar.Method)
                        {
                        case InlineParseMethod.BoldItalic:
                            parseResult = BoldItalicTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.LinkReference:
                            parseResult = LinkAnchorInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Bold:
                            parseResult = BoldTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Italic:
                            parseResult = ItalicTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.MarkdownLink:
                            if (!ignoreLinks)
                            {
                                parseResult = MarkdownLinkInline.Parse(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.AngleBracketLink:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParseAngleBracketLink(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.Url:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParseUrl(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.RedditLink:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParseRedditLink(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.PartialLink:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParsePartialLink(markdown, pos, end);
                            }

                            break;

                        case InlineParseMethod.Email:
                            if (!ignoreLinks)
                            {
                                parseResult = HyperlinkInline.ParseEmailAddress(markdown, start, pos, end);
                            }

                            break;

                        case InlineParseMethod.Strikethrough:
                            parseResult = StrikethroughTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Spoiler:
                            parseResult = SpoilerTextInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Code:
                            parseResult = CodeInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Image:
                            parseResult = ImageInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Emoji:
                            parseResult = EmojiInline.Parse(markdown, pos, end);
                            break;

                        case InlineParseMethod.Discord:
                            parseResult = DiscordInline.Parse(markdown, pos, end);
                            break;
                        }

                        if (parseResult != null)
                        {
                            return(parseResult);
                        }
                    }
                }
            }

            // If we didn't find any elements we have a normal text block.
            // Let us consume the entire range.
            return(new InlineParseResult(TextRunInline.Parse(markdown, start, end), start, end));
        }
        protected override void RenderSpoiler(SpoilerTextInline element, IRenderContext context)
        {
            if (!(context is InlineRenderContext localContext))
            {
                throw new RenderContextIncorrectException();
            }

            // TODO (maybe): make this shit actually work?

            if (localContext.Parent is Hyperlink)
            {
                // In case of Hyperlink, break glass (or add a run).

                var span         = new Span();
                var childContext = new InlineRenderContext(span.Inlines, context)
                {
                    Parent = span
                };

                // Render the children into the inline.
                RenderInlineChildren(element.Inlines, childContext);

                // Add it to the current inlines
                localContext.InlineCollection.Add(span);
            }
            else
            {
                var text         = CreateTextBlock(localContext);
                var childContext = new InlineRenderContext(text.Inlines, context)
                {
                    Parent = text
                };

                RenderInlineChildren(element.Inlines, childContext);

                if (localContext.WithinItalics)
                {
                    text.FontStyle = FontStyle.Italic;
                }

                if (localContext.WithinBold)
                {
                    text.FontWeight = FontWeights.Bold;
                }

                var borderthickness = InlineCodeBorderThickness;
                var padding         = InlineCodePadding;
                var spacingoffset   = -(borderthickness.Bottom + padding.Bottom);
                var margin          = new Thickness(0, spacingoffset, 0, spacingoffset);

                var border = new Border
                {
                    BorderThickness = borderthickness,
                    BorderBrush     = InlineCodeBorderBrush,
                    Background      = InlineCodeBackground,
                    Child           = text,
                    Padding         = padding,
                    Margin          = margin
                };

                // Aligns content in InlineUI, see https://social.msdn.microsoft.com/Forums/silverlight/en-US/48b5e91e-efc5-4768-8eaf-f897849fcf0b/richtextbox-inlineuicontainer-vertical-alignment-issue?forum=silverlightarchieve
                border.RenderTransform = new TranslateTransform
                {
                    Y = 4
                };

                if (App.RoamingSettings.Read(Constants.ENABLE_SPOILERS, true))
                {
                    text.Opacity   = 0;
                    border.Tapped += (o, e) =>
                    {
                        text.Opacity = 1;
                    };
                }

                var inlineUIContainer = new InlineUIContainer
                {
                    Child = border,
                };

                RootElement.Margin = new Thickness(0, 0, 0, 4);

                // Add it to the current inlines
                localContext.InlineCollection.Add(inlineUIContainer);
            }
        }
Exemple #4
0
        protected override void RenderSpoiler(SpoilerTextInline element, IRenderContext context)
        {
            if (!(context is InlineRenderContext localContext))
            {
                throw new RenderContextIncorrectException();
            }

            // TODO (maybe): make this shit actually work?

            if (localContext.Parent is Hyperlink)
            {
                // In case of Hyperlink, break glass (or add a run).

                var span         = new Span();
                var childContext = new InlineRenderContext(span.Inlines, context)
                {
                    Parent = span
                };

                // Render the children into the inline.
                RenderInlineChildren(element.Inlines, childContext);

                // Add it to the current inlines
                localContext.InlineCollection.Add(span);
            }
            else
            {
                var text = new RichTextBlock
                {
                    CharacterSpacing       = CharacterSpacing,
                    FontFamily             = FontFamily,
                    FontSize               = FontSize,
                    FontStretch            = FontStretch,
                    FontStyle              = FontStyle,
                    FontWeight             = FontWeight,
                    Foreground             = localContext.Foreground,
                    IsTextSelectionEnabled = IsTextSelectionEnabled,
                    TextWrapping           = TextWrapping
                };

                var paragraph    = new Paragraph();
                var childContext = new InlineRenderContext(paragraph.Inlines, context)
                {
                    Parent = text
                };

                RenderInlineChildren(element.Inlines, childContext);

                if (localContext.WithinItalics)
                {
                    text.FontStyle = FontStyle.Italic;
                }

                if (localContext.WithinBold)
                {
                    text.FontWeight = FontWeights.Bold;
                }

                if (localContext.WithinUnderline)
                {
                    text.TextDecorations = TextDecorations.Underline;
                }

                text.Blocks.Add(paragraph);

                var borderthickness = InlineCodeBorderThickness;
                var padding         = InlineCodePadding;
                var spacingoffset   = -(borderthickness.Bottom + padding.Bottom);
                var margin          = new Thickness(0, spacingoffset, 0, spacingoffset);

                var grid = new Grid
                {
                    BorderThickness = borderthickness,
                    BorderBrush     = InlineCodeBorderBrush,
                    Background      = InlineCodeBackground,
                    Padding         = padding,
                    Margin          = margin
                };

                // Aligns content in InlineUI, see https://social.msdn.microsoft.com/Forums/silverlight/en-US/48b5e91e-efc5-4768-8eaf-f897849fcf0b/richtextbox-inlineuicontainer-vertical-alignment-issue?forum=silverlightarchieve
                grid.RenderTransform = new TranslateTransform
                {
                    Y = 4
                };

                grid.Children.Add(text);

                if (App.RoamingSettings.Read(Constants.ENABLE_SPOILERS, true))
                {
                    var border = new Border()
                    {
                        Background          = InlineCodeBackground,
                        HorizontalAlignment = HorizontalAlignment.Stretch,
                        VerticalAlignment   = VerticalAlignment.Stretch
                    };

                    border.Tapped += (o, e) => { border.Opacity = 0; };

                    grid.Children.Add(border);
                }

                var inlineUIContainer = new InlineUIContainer
                {
                    Child = grid,
                };

                RootElement.Margin = new Thickness(0, 0, 0, 4);

                // Add it to the current inlines
                localContext.InlineCollection.Add(inlineUIContainer);
            }
        }
Exemple #5
0
 /// <summary>
 /// Renders a Spoiler element
 /// </summary>
 /// <param name="element"> The parsed inline element to render. </param>
 /// <param name="context"> Persistent state. </param>
 protected abstract void RenderSpoiler(SpoilerTextInline element, IRenderContext context);