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(); }
/// <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); } }
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); } }
/// <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);