/// <summary> /// Creates the rules that convert <see cref="BBCode"/> to HTML /// </summary> /// <param name="messageId"> /// The message Id. /// </param> /// <param name="ruleEngine"> /// The rule Engine. /// </param> /// <param name="doFormatting"> /// The do Formatting. /// </param> /// <param name="targetBlankOverride"> /// The target Blank Override. /// </param> /// <param name="useNoFollow"> /// The use No Follow. /// </param> /// <param name="isEditMode"> /// Indicates if the formatting is for the Editor. /// </param> public void CreateBBCodeRules( [NotNull] int messageId, IProcessReplaceRules ruleEngine, bool doFormatting, bool targetBlankOverride, bool useNoFollow, bool isEditMode = false) { var target = this.Get <BoardSettings>().BlankLinks || targetBlankOverride ? "target=\"_blank\"" : string.Empty; var noFollow = useNoFollow ? "rel=\"nofollow\"" : string.Empty; // pull localized strings var localQuoteStr = this.Get <ILocalization>().GetText("COMMON", "BBCODE_QUOTE"); // handle font sizes -- this rule class internally handles the "size" variable ruleEngine.AddRule( new FontSizeRegexReplaceRule( @"\[size=(?<size>(.*?))\](?<inner>(.*?))\[/size\]", @"<span style=""font-size:${size}"">${inner}</span>", Options)); if (doFormatting) { ruleEngine.AddRule( new CodeRegexReplaceRule( new Regex(@"\[noparse\](?<inner>(.*?))\[/noparse\]", Options | RegexOptions.Compiled), @"${inner}")); ruleEngine.AddRule( new SimpleRegexReplaceRule( new Regex(@"\[B\](?<inner>(.*?))\[/B\]", Options | RegexOptions.Compiled), "<strong>${inner}</strong>")); ruleEngine.AddRule( new SimpleRegexReplaceRule(@"\[S\](?<inner>(.*?))\[/S\]", "<s>${inner}</s>", Options)); ruleEngine.AddRule( new SimpleRegexReplaceRule(@"\[I\](?<inner>(.*?))\[/I\]", "<em>${inner}</em>", Options)); ruleEngine.AddRule( new SimpleRegexReplaceRule(@"\[U\](?<inner>(.*?))\[/U\]", "<u>${inner}</u>", Options)); ruleEngine.AddRule( new SimpleRegexReplaceRule(@"\[h\](?<inner>(.*?))\[/h\]", "<mark>${inner}</mark>", Options)); // e-mails ruleEngine.AddRule( new VariableRegexReplaceRule( new Regex( @"\[email=(?<email>[^\]]*)\](?<inner>([^""\r\n\]\[]+?))\[/email\]", Options | RegexOptions.Compiled), "<a href=\"mailto:${email}\">${inner} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>", new[] { "email" })); ruleEngine.AddRule( new SimpleRegexReplaceRule( new Regex( @"\[email[^\]]*\](?<inner>([^""\r\n\]\[]+?))\[/email\]", Options | RegexOptions.Compiled), @"<a href=""mailto:${inner}"">${inner}</a>")); // urls ruleEngine.AddRule( new VariableRegexReplaceRule( new Regex( @"\[url\=(?<http>(skype:)|(http://)|(https://)|(ftp://)|(ftps://))?(?<url>([^javascript:])([^""\r\n\]\[]*?))\](?<inner>(.+?))\[/url\]", Options | RegexOptions.Compiled), "<a {0} {1} href=\"${http}${url}\" title=\"${http}${url}\">${inner} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>" .Replace("{0}", target).Replace("{1}", noFollow), new[] { "url", "http" }, new[] { string.Empty, string.Empty // "http://" }) { RuleRank = 10 }); ruleEngine.AddRule( new VariableRegexReplaceRule( new Regex( @"\[url\](?<http>(skype:)|(http://)|(https://)|(ftp://)|(ftps://)|(mailto:))?(?<inner>([^javascript:])(.+?))\[/url\]", Options | RegexOptions.Compiled), "<a {0} {1} href=\"${http}${inner}\" title=\"${http}${inner}\">${http}${innertrunc} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>" .Replace("{0}", target).Replace("{1}", noFollow), new[] { "http" }, new[] { string.Empty, string.Empty // "http://" }, 50) { RuleRank = 11 }); // urls ruleEngine.AddRule( new VariableRegexReplaceRule( new Regex( @"(?<before>^|[ ]|\[[A-Za-z0-9]\]|\[\*\]|[A-Za-z0-9])(?<!"")(?<!href="")(?<!src="")(?<inner>(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled), "${before}<a {0} {1} href=\"${inner}\" title=\"${inner}\">${innertrunc} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>" .Replace("{0}", target).Replace("{1}", noFollow), new[] { "before" }, new[] { string.Empty }, 50) { RuleRank = 12 }); ruleEngine.AddRule( new VariableRegexReplaceRule( new Regex( @"(?<before>^|[ ]|\[[A-Za-z0-9]\]|\[\*\]|[A-Za-z0-9])(?<!href="")(?<!src="")(?<inner>(http://|https://|ftp://)(?:[\w-]+\.)+[\w-]+(?:/[\w-./?%&=+;,:#~/(/)$]*[^.<|^.\[])?)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled), "${before}<a {0} {1} href=\"${inner}\" title=\"${inner}\">${innertrunc} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>" .Replace("{0}", target).Replace("{1}", noFollow), new[] { "before" }, new[] { string.Empty }, 50) { RuleRank = 13 }); // font ruleEngine.AddRule( new VariableRegexReplaceRule( @"\[font=(?<font>([-a-z0-9, ]*))\](?<inner>(.*?))\[/font\]", "<span style=\"font-family:${font}\">${inner}</span>", Options, new[] { "font" })); // color ruleEngine.AddRule( new VariableRegexReplaceRule( @"\[color=(?<color>(\#?[-a-z0-9]*))\](?<inner>(.*?))\[/color\]", "<span style=\"color:${color}\">${inner}</span>", Options, new[] { "color" })); // lists ruleEngine.AddRule( new SimpleRegexReplaceRule(@"\[list\](?<inner>(.*?))\[/list\]", "<ul>${inner}</ul>", Options)); ruleEngine.AddRule( new SimpleRegexReplaceRule( @"\[list=1\](?<inner>(.*?))\[/list\]", "<ol style=\"list-style-type:number\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule( new SimpleRegexReplaceRule( @"\[list=i\](?<inner>(.*?))\[/list\]", "<ol style=\"list-style-type:lower-roman\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule( new SimpleRegexReplaceRule( @"\[list=I\](?<inner>(.*?))\[/list\]", "<ol style=\"list-style-type:upper-roman\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule( new SimpleRegexReplaceRule( @"\[list=a\](?<inner>(.*?))\[/list\]", "<ol style=\"list-style-type:lower-alpha\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule( new SimpleRegexReplaceRule( @"\[list=A\](?<inner>(.*?))\[/list\]", "<ol style=\"list-style-type:upper-alpha\">${inner}</ol>", RegexOptions.Singleline)); // bullets ruleEngine.AddRule(new SingleRegexReplaceRule(@"\[\*\]", "<li>", Options)); // alignment ruleEngine.AddRule( new SimpleRegexReplaceRule( @"\[center\](?<inner>(.*?))\[/center\]", "<div align=\"center\">${inner}</div>", Options)); ruleEngine.AddRule( new SimpleRegexReplaceRule( @"\[left\](?<inner>(.*?))\[/left\]", "<div align=\"left\">${inner}</div>", Options)); ruleEngine.AddRule( new SimpleRegexReplaceRule( @"\[right\](?<inner>(.*?))\[/right\]", "<div align=\"right\">${inner}</div>", Options)); // indent ruleEngine.AddRule( new SimpleRegexReplaceRule( @"\[indent\](?<inner>(.*?))\[/indent\]", "<div style=\"margin-left:40px\">${inner}</div>", Options)); string imageHtml; string imageHtmlWithDesc; if (messageId > 0) { imageHtml = "<a href=\"${http}${inner}\" data-gallery=\"#blueimp-gallery-" + messageId + "\"><img src=\"${http}${inner}\" alt=\"UserPostedImage\" class=\"img-user-posted img-thumbnail\" style=\"max-height:${height}px;\"></a>"; imageHtmlWithDesc = "<a href=\"${http}${inner}\" alt=\"${description}\" title=\"${description}\" data-gallery=\"#blueimp-gallery-" + messageId + "\"><img src=\"${http}${inner}\" alt=\"UserPostedImage\" class=\"img-user-posted img-thumbnail\" style=\"max-height:${height}px;\"></a>"; } else { imageHtml = "<img src=\"${http}${inner}\" alt=\"UserPostedImage\" class=\"img-user-posted img-thumbnail\" style=\"max-height:${height}px;\">"; imageHtmlWithDesc = "<img src=\"${http}${inner}\" alt=\"${description}\" title=\"${description}\" class=\"img-user-posted img-thumbnail\" style=\"max-height:${height}px;\">"; } // image ruleEngine.AddRule( new VariableRegexReplaceRule( new Regex( @"\[img\](?<http>(http://)|(https://)|(ftp://)|(ftps://))?(?<inner>((?!.+logout)[^""\r\n\]\[]+?\.((googleusercontent[^\[]*)|(jpg[^\[]*)|(jpeg[^\[]*)|(bmp[^\[]*)|(png[^\[]*)|(gif[^\[]*)|(tif[^\[]*)|(ashx[^\[]*)|(php[^\[]*)|(aspx[^\[]*))))\[/img\]", Options | RegexOptions.Compiled), imageHtml, new[] { "http", "height" }, new[] { "http://", this.Get <BoardSettings>().ImageThumbnailMaxHeight.ToString() }) { RuleRank = 70 }); ruleEngine.AddRule( new VariableRegexReplaceRule( new Regex( @"\[img=(?<http>(http://)|(https://)|(ftp://)|(ftps://))?(?<inner>((?!.+logout)[^""\r\n\]\[]+?\.((googleusercontent[^\[]*)|(jpg[^\]\[/img\]]*)|(jpeg[^\[\[/img\]]*)|(bmp[^\[\[/img\]]*)|(png[^\]\[/img\]]*)|(gif[^\]\[/img\]]*)|(tif[^\]\[/img\]]*)|(ashx[^\]\[/img\]]*)|(php[^\]\[/img\]]*)|(aspx[^\]\[/img\]]*))))\]\[/img\]", Options | RegexOptions.Compiled), imageHtml, new[] { "http", "height" }, new[] { "http://", this.Get <BoardSettings>().ImageThumbnailMaxHeight.ToString() }) { RuleRank = 71 }); ruleEngine.AddRule( new VariableRegexReplaceRule( new Regex( @"\[img=(?<http>(http://)|(https://)|(ftp://)|(ftps://))?(?<inner>((?!.+logout)[^""\r\n\]\[]+?\.((googleusercontent[^\[]*)|(jpg[^\]]*)|(jpeg[^\]]*)|(bmp[^\]]*)|(png[^\]]*)|(gif[^\]]*)|(tif[^\]]*)|(ashx[^\]]*)|(php[^\]]*)|(aspx[^\]]*))))\](?<description>[^\[]*)\[/img\]", Options | RegexOptions.Compiled), imageHtmlWithDesc, new[] { "http", "description", "height" }, new[] { "http://", string.Empty, this.Get <BoardSettings>().ImageThumbnailMaxHeight.ToString() }) { RuleRank = 72 }); // basic hr and br rules var horizontalLineRule = new SingleRegexReplaceRule( "^[-][-][-][-][-]*[\r]?[\n]", "<hr />", RegexOptions.IgnoreCase | RegexOptions.Multiline); ruleEngine.AddRule(new SingleRegexReplaceRule(@"\[br\]", "</p>", Options)); // Multiline, since ^ must match beginning of line var breakRule = new SingleRegexReplaceRule( "\r\n", "<br />", RegexOptions.IgnoreCase | RegexOptions.Multiline) { RuleRank = horizontalLineRule.RuleRank + 1 }; // Ensure the newline rule is processed after the HR rule, otherwise the newline characters in the HR regex will never match ruleEngine.AddRule(horizontalLineRule); ruleEngine.AddRule(isEditMode ? breakRule : new SingleRegexReplaceRule(@"\r\n", "<p>", Options)); } // add rule for code block type with syntax highlighting ruleEngine.AddRule( new SyntaxHighlighterRegexReplaceRule( isEditMode, new Regex(@"\[code=(?<language>[^\]]*)\](?<inner>(.*?))\[/code\]\r\n|\[code=(?<language>[^\]]*)\](?<inner>(.*?))\[/code\]", Options), @"<div class=""code"">${inner}</div>") { RuleRank = 2 }); // handle custom BBCode this.AddCustomBBCodeRules(ruleEngine); // add rule for code block type with no syntax highlighting ruleEngine.AddRule( new SyntaxHighlighterRegexReplaceRule( isEditMode, new Regex(@"\[code\](?<inner>(.*?))\[/code\]\r\n|\[code\](?<inner>(.*?))\[/code\]", Options), @"<div class=""code"">${inner}</div>")); ruleEngine.AddRule( new QuoteRegexReplaceRule( @"\[quote=(?<quote>(.*?))]", @"<blockquote class=""blockquote blockquote-custom pt-3 px-1 pb-1 mb-4 border border-secondary rounded""> <div class=""blockquote-custom-icon bg-secondary""> <i class=""fa fa-quote-left fa-sm link-light""></i> </div>${quote}", Options)); // simple open quote tag var simpleOpenQuoteReplace = $@"<blockquote class=""blockquote blockquote-custom pt-3 px-1 pb-1 mb-4 border border-secondary rounded""> <div class=""blockquote-custom-icon bg-secondary""> <i class=""fa fa-quote-left fa-sm link-light""></i> </div> <footer class=""blockquote-footer""><cite>{localQuoteStr}</cite></footer> <p class=""mb-0"">"; ruleEngine.AddRule( new SimpleRegexReplaceRule(@"\[quote\]", simpleOpenQuoteReplace, Options) { RuleRank = 62 }); // and finally the closing quote tag ruleEngine.AddRule( new SingleRegexReplaceRule(@"\[/quote\]", "</p></blockquote>", Options) { RuleRank = 63 }); }
/// <summary> /// Creates the rules that convert <see cref="YafBBCode" /> to HTML /// </summary> /// <param name="ruleEngine">The rule Engine.</param> /// <param name="isHtml">if set to <c>true</c> [is HTML].</param> /// <param name="doFormatting">The do Formatting.</param> /// <param name="targetBlankOverride">The target Blank Override.</param> /// <param name="useNoFollow">The use No Follow.</param> /// <param name="convertBBQuotes">The convert BB Quotes.</param> public void CreateBBCodeRules( IProcessReplaceRules ruleEngine, bool isHtml, bool doFormatting, bool targetBlankOverride, bool useNoFollow, bool convertBBQuotes) { string target = (this.Get <YafBoardSettings>().BlankLinks || targetBlankOverride) ? "target=\"_blank\"" : string.Empty; string nofollow = useNoFollow ? "rel=\"nofollow\"" : string.Empty; const string ClassModal = ""; // pull localized strings string localQuoteStr = this.Get <ILocalization>().GetText("COMMON", "BBCODE_QUOTE"); string localCodeStr = this.Get <ILocalization>().GetText("COMMON", "BBCODE_CODE"); // handle font sizes -- this rule class internally handles the "size" variable ruleEngine.AddRule( new FontSizeRegexReplaceRule( @"\[size=(?<size>(.*?))\](?<inner>(.*?))\[/size\]", @"<span style=""font-size:${size}"">${inner}</span>", _Options)); if (doFormatting) { ruleEngine.AddRule( new CodeRegexReplaceRule( _rgxNoParse, @"${inner}")); ruleEngine.AddRule(new SimpleRegexReplaceRule(_rgxBold, "<strong>${inner}</strong>")); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxStrike, "<s>${inner}</s>", _Options)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxItalic, "<em>${inner}</em>", _Options)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxUnderline, "<u>${inner}</u>", _Options)); ruleEngine.AddRule( new SimpleRegexReplaceRule(_RgxHighlighted, @"<span class=""highlight"">${inner}</span>", _Options)); // e-mails ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxEmail2, "<a href=\"mailto:${email}\">${inner}</a>", new[] { "email" })); ruleEngine.AddRule(new SimpleRegexReplaceRule(_rgxEmail1, @"<a href=""mailto:${inner}"">${inner}</a>")); // urls ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxUrl2, "<a {0} {1} href=\"${http}${url}\" title=\"${http}${url}\">${inner}</a>".Replace("{0}", target) .Replace("{1}", nofollow), new[] { "url", "http" }, new[] { string.Empty, string.Empty // "http://" }) { RuleRank = 10 }); ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxUrl1, "<a {0} {1} href=\"${http}${inner}\" title=\"${http}${inner}\">${http}${innertrunc}</a>".Replace("{0}", target).Replace("{1}", nofollow), new[] { "http" }, new[] { string.Empty, string.Empty // "http://" }, 50) { RuleRank = 11 }); // urls ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxModalUrl2, "<a {0} {1} {2} href=\"#\" data-href=\"${http}${url}\" title=\"${http}${url}\">${inner}</a>".Replace("{0}", target).Replace("{1}", nofollow).Replace("{2}", ClassModal), new[] { "url", "http" }, new[] { string.Empty, string.Empty // "http://" })); ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxModalUrl1, "<a {0} {1} {2} href=\"#\" data-href=\"${http}${inner}\" title=\"${http}${inner}\">${http}${innertrunc}</a>".Replace("{0}", target).Replace("{1}", nofollow).Replace("{2}", ClassModal), new[] { "http" }, new[] { string.Empty, string.Empty // "http://" }, 50)); // font ruleEngine.AddRule( new VariableRegexReplaceRule( _RgxFont, "<span style=\"font-family:${font}\">${inner}</span>", _Options, new[] { "font" })); // color ruleEngine.AddRule( new VariableRegexReplaceRule( _RgxColor, "<span style=\"color:${color}\">${inner}</span>", _Options, new[] { "color" })); // lists ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxList1, "<ul>${inner}</ul>", _Options)); /*ruleEngine.AddRule( * new VariableRegexReplaceRule(_rgxList2, "<ol type=\"${type}\">${inner}</ol>", _options, new[] { "type" }));*/ ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxListNumber, "<ol style=\"list-style-type:number\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxListLowerRoman, "<ol style=\"list-style-type:lower-roman\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxListUpperRoman, "<ol style=\"list-style-type:upper-roman\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxListLowerAlpha, "<ol style=\"list-style-type:lower-alpha\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxListUpperAlpha, "<ol style=\"list-style-type:upper-alpha\">${inner}</ol>", RegexOptions.Singleline)); // bullets ruleEngine.AddRule(new SingleRegexReplaceRule(_RgxBullet, "<li>", _Options)); // alignment ruleEngine.AddRule( new SimpleRegexReplaceRule(_RgxCenter, "<div align=\"center\">${inner}</div>", _Options)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxLeft, "<div align=\"left\">${inner}</div>", _Options)); ruleEngine.AddRule( new SimpleRegexReplaceRule(_RgxRight, "<div align=\"right\">${inner}</div>", _Options)); // indent ruleEngine.AddRule( new SimpleRegexReplaceRule(_RgxIndent, "<div style=\"margin-left:40px\">${inner}</div>", _Options)); // add max-width and max-height to posted Image var maxWidth = this.Get <YafBoardSettings>().ImageAttachmentResizeWidth; var maxHeight = this.Get <YafBoardSettings>().ImageAttachmentResizeHeight; string styleAttribute = this.Get <YafBoardSettings>().ResizePostedImages ? " style=\"max-width:{0}px;max-height:{1}px\"".FormatWith( maxWidth, maxHeight) : string.Empty; // image ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxImg, "<img src=\"${http}${inner}\" alt=\"UserPostedImage\" class=\"UserPostedImage\"{0} />".Replace( "{0}", styleAttribute), new[] { "http" }, new[] { "http://" }) { RuleRank = 70 }); ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxImgEmptyTitle, "<img src=\"${http}${inner}\" alt=\"UserPostedImage\" class=\"UserPostedImage\"{0} />".Replace( "{0}", styleAttribute), new[] { "http" }, new[] { "http://" }) { RuleRank = 71 }); ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxImgTitle, "<img src=\"${http}${inner}\" alt=\"${description}\" title=\"${description}\" class=\"UserPostedImage\"{0} />" .Replace("{0}", styleAttribute), new[] { "http", "description" }, new[] { "http://", string.Empty }) { RuleRank = 72 }); // basic hr and br rules var hrRule = new SingleRegexReplaceRule( _RgxHr, "<hr />", RegexOptions.IgnoreCase | RegexOptions.Multiline); ruleEngine.AddRule( new SingleRegexReplaceRule(@"\[br\]", "</p>", _Options)); // Multiline, since ^ must match beginning of line var brRule = new SingleRegexReplaceRule( _RgxBr, "<br />", RegexOptions.IgnoreCase | RegexOptions.Multiline) { RuleRank = hrRule.RuleRank + 1 }; // Ensure the newline rule is processed after the HR rule, otherwise the newline characters in the HR regex will never match ruleEngine.AddRule(hrRule); if (!isHtml) { ruleEngine.AddRule(brRule); } else { // handle paragraphs ruleEngine.AddRule( new SingleRegexReplaceRule(@"\r\n", "<p>", _Options)); } } // add smilies this.AddSmiles(ruleEngine); if (convertBBQuotes) { // add rule for code block type with syntax highlighting ruleEngine.AddRule( new SyntaxHighlightedCodeRegexReplaceRule( _regexCodeWithLanguage, @"<div class=""code""><strong>{0}</strong><div class=""innercode"">${inner}</div></div>".Replace("{0}", localCodeStr)) { RuleRank = 30 }); // handle custom YafBBCode this.AddCustomBBCodeRules(ruleEngine); // add rule for code block type with no syntax highlighting ruleEngine.AddRule( new SyntaxHighlightedCodeRegexReplaceRule( _rgxCode1, @"<div class=""code""><strong>{0}</strong><div class=""innercode"">${inner}</div></div>".Replace("{0}", localCodeStr))); ruleEngine.AddRule( new QuoteRegexReplaceRule( OpenQuoteUserIdRegex, @"<div class=""quote""><span class=""quotetitle"">${quote}</span><div class=""innerquote"">", _Options)); // simple open quote tag var simpleOpenQuoteReplace = @"<div class=""quote""><span class=""quotetitle"">{0}</span><div class=""innerquote"">" .FormatWith(localQuoteStr); ruleEngine.AddRule( new SimpleRegexReplaceRule(OpenQuoteRegex, simpleOpenQuoteReplace, _Options) { RuleRank = 62 }); // and finally the closing quote tag ruleEngine.AddRule( new SingleRegexReplaceRule(CloseQuoteRegex, "</div></div>", _Options) { RuleRank = 63 }); } // post and topic rules... ruleEngine.AddRule( new PostTopicRegexReplaceRule( _RgxPost, @"<a href=""${post}"" title=""${inner}"">${inner}</a>", _Options)); ruleEngine.AddRule( new PostTopicRegexReplaceRule( _RgxTopic, @"<a href=""${topic}"" title=""${inner}"">${inner}</a>", _Options)); }
/// <summary> /// Creates the rules that convert <see cref="YafBBCode" /> to HTML /// </summary> /// <param name="ruleEngine">The rule Engine.</param> /// <param name="isHtml">if set to <c>true</c> [is HTML].</param> /// <param name="doFormatting">The do Formatting.</param> /// <param name="targetBlankOverride">The target Blank Override.</param> /// <param name="useNoFollow">The use No Follow.</param> /// <param name="convertBBQuotes">The convert BB Quotes.</param> public void CreateBBCodeRules( IProcessReplaceRules ruleEngine, bool isHtml, bool doFormatting, bool targetBlankOverride, bool useNoFollow, bool convertBBQuotes) { var target = this.Get <YafBoardSettings>().BlankLinks || targetBlankOverride ? "target=\"_blank\"" : string.Empty; var nofollow = useNoFollow ? "rel=\"nofollow\"" : string.Empty; var classModal = string.Empty; // pull localized strings var localQuoteStr = this.Get <ILocalization>().GetText("COMMON", "BBCODE_QUOTE"); // handle font sizes -- this rule class internally handles the "size" variable ruleEngine.AddRule( new FontSizeRegexReplaceRule( @"\[size=(?<size>(.*?))\](?<inner>(.*?))\[/size\]", @"<span style=""font-size:${size}"">${inner}</span>", Options)); if (doFormatting) { ruleEngine.AddRule(new CodeRegexReplaceRule(_rgxNoParse, @"${inner}")); ruleEngine.AddRule(new SimpleRegexReplaceRule(_rgxBold, "<strong>${inner}</strong>")); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxStrike, "<s>${inner}</s>", Options)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxItalic, "<em>${inner}</em>", Options)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxUnderline, "<u>${inner}</u>", Options)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxHighlighted, @"<mark>${inner}</mark>", Options)); // e-mails ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxEmail2, "<a href=\"mailto:${email}\">${inner} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>", new[] { "email" })); ruleEngine.AddRule(new SimpleRegexReplaceRule(_rgxEmail1, @"<a href=""mailto:${inner}"">${inner}</a>")); // urls ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxUrl2, "<a {0} {1} href=\"${http}${url}\" title=\"${http}${url}\">${inner} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>" .Replace("{0}", target).Replace("{1}", nofollow), new[] { "url", "http" }, new[] { string.Empty, string.Empty // "http://" }) { RuleRank = 10 }); ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxUrl1, "<a {0} {1} href=\"${http}${inner}\" title=\"${http}${inner}\">${http}${innertrunc} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>" .Replace("{0}", target).Replace("{1}", nofollow), new[] { "http" }, new[] { string.Empty, string.Empty // "http://" }, 50) { RuleRank = 11 }); // urls ruleEngine.AddRule( new VariableRegexReplaceRule( _RgxUrl3, "${before}<a {0} {1} href=\"${inner}\" title=\"${inner}\">${innertrunc} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>" .Replace("{0}", target).Replace("{1}", nofollow), new[] { "before" }, new[] { string.Empty }, 50) { RuleRank = 12 }); ruleEngine.AddRule( new VariableRegexReplaceRule( _RgxUrl4, "${before}<a {0} {1} href=\"${inner}\" title=\"${inner}\">${innertrunc} <i class=\"fa fa-external-link-alt fa-fw\"></i></a>" .Replace("{0}", target).Replace("{1}", nofollow), new[] { "before" }, new[] { string.Empty }, 50) { RuleRank = 13 }); ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxModalUrl2, "<a {0} {1} {2} href=\"#\" data-href=\"${http}${url}\" title=\"${http}${url}\">${inner}</a>" .Replace("{0}", target).Replace("{1}", nofollow).Replace("{2}", classModal), new[] { "url", "http" }, new[] { string.Empty, string.Empty // "http://" })); ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxModalUrl1, "<a {0} {1} {2} href=\"#\" data-href=\"${http}${inner}\" title=\"${http}${inner}\">${http}${innertrunc}</a>" .Replace("{0}", target).Replace("{1}", nofollow).Replace("{2}", classModal), new[] { "http" }, new[] { string.Empty, string.Empty // "http://" }, 50)); // font ruleEngine.AddRule( new VariableRegexReplaceRule( _RgxFont, "<span style=\"font-family:${font}\">${inner}</span>", Options, new[] { "font" })); // color ruleEngine.AddRule( new VariableRegexReplaceRule( _RgxColor, "<span style=\"color:${color}\">${inner}</span>", Options, new[] { "color" })); // lists ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxList1, "<ul>${inner}</ul>", Options)); /*ruleEngine.AddRule( * new VariableRegexReplaceRule(_rgxList2, "<ol type=\"${type}\">${inner}</ol>", _options, new[] { "type" }));*/ ruleEngine.AddRule( new SimpleRegexReplaceRule( _RgxListNumber, "<ol style=\"list-style-type:number\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule( new SimpleRegexReplaceRule( _RgxListLowerRoman, "<ol style=\"list-style-type:lower-roman\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule( new SimpleRegexReplaceRule( _RgxListUpperRoman, "<ol style=\"list-style-type:upper-roman\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule( new SimpleRegexReplaceRule( _RgxListLowerAlpha, "<ol style=\"list-style-type:lower-alpha\">${inner}</ol>", RegexOptions.Singleline)); ruleEngine.AddRule( new SimpleRegexReplaceRule( _RgxListUpperAlpha, "<ol style=\"list-style-type:upper-alpha\">${inner}</ol>", RegexOptions.Singleline)); // bullets ruleEngine.AddRule(new SingleRegexReplaceRule(_RgxBullet, "<li>", Options)); // alignment ruleEngine.AddRule( new SimpleRegexReplaceRule(_RgxCenter, "<div align=\"center\">${inner}</div>", Options)); ruleEngine.AddRule(new SimpleRegexReplaceRule(_RgxLeft, "<div align=\"left\">${inner}</div>", Options)); ruleEngine.AddRule( new SimpleRegexReplaceRule(_RgxRight, "<div align=\"right\">${inner}</div>", Options)); // indent ruleEngine.AddRule( new SimpleRegexReplaceRule(_RgxIndent, "<div style=\"margin-left:40px\">${inner}</div>", Options)); // image ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxImg, "<img src=\"${http}${inner}\" alt=\"UserPostedImage\" class=\"img-user-posted img-thumbnail\" style=\"max-width:auto;max-height:${height}px;\" />", new[] { "http", "height" }, new[] { "http://", this.Get <YafBoardSettings>().ImageThumbnailMaxHeight.ToString() }) { RuleRank = 70 }); ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxImgEmptyTitle, "<img src=\"${http}${inner}\" alt=\"UserPostedImage\" class=\"img-user-posted img-thumbnail\" style=\"max-width:auto;max-height:${height}px;\" />", new[] { "http", "height" }, new[] { "http://", this.Get <YafBoardSettings>().ImageThumbnailMaxHeight.ToString() }) { RuleRank = 71 }); ruleEngine.AddRule( new VariableRegexReplaceRule( _rgxImgTitle, "<img src=\"${http}${inner}\" alt=\"${description}\" title=\"${description}\" class=\"img-user-posted img-thumbnail\" style=\"max-width:auto;max-height:${height}px;\" />", new[] { "http", "description", "height" }, new[] { "http://", string.Empty, this.Get <YafBoardSettings>().ImageThumbnailMaxHeight.ToString() }) { RuleRank = 72 }); // basic hr and br rules var hrRule = new SingleRegexReplaceRule( _RgxHr, "<hr />", RegexOptions.IgnoreCase | RegexOptions.Multiline); ruleEngine.AddRule(new SingleRegexReplaceRule(@"\[br\]", "</p>", Options)); // Multiline, since ^ must match beginning of line var brRule = new SingleRegexReplaceRule( _RgxBr, "<br />", RegexOptions.IgnoreCase | RegexOptions.Multiline) { RuleRank = hrRule.RuleRank + 1 }; // Ensure the newline rule is processed after the HR rule, otherwise the newline characters in the HR regex will never match ruleEngine.AddRule(hrRule); ruleEngine.AddRule(!isHtml ? brRule : new SingleRegexReplaceRule(@"\r\n", "<p>", Options)); } if (convertBBQuotes) { // add rule for code block type with syntax highlighting ruleEngine.AddRule( new SyntaxHighlightedCodeRegexReplaceRule( _regexCodeWithLanguage, @"<div class=""code"">${inner}</div>") { RuleRank = 2 }); // handle custom YafBBCode this.AddCustomBBCodeRules(ruleEngine); // add rule for code block type with no syntax highlighting ruleEngine.AddRule( new SyntaxHighlightedCodeRegexReplaceRule(_rgxCode1, @"<div class=""code"">${inner}</div>")); ruleEngine.AddRule( new QuoteRegexReplaceRule( OpenQuoteUserIdRegex, @"<div class=""card bg-light mb-3"">${quote}", Options)); // simple open quote tag var simpleOpenQuoteReplace = $@"<div class=""card bg-light mb-3""><div class=""card-header text-muted"">{localQuoteStr}</div><div class=""card-body""><p class=""card-text"">"; ruleEngine.AddRule( new SimpleRegexReplaceRule(OpenQuoteRegex, simpleOpenQuoteReplace, Options) { RuleRank = 62 }); // and finally the closing quote tag ruleEngine.AddRule( new SingleRegexReplaceRule(CloseQuoteRegex, "</div></div>", Options) { RuleRank = 63 }); } // post and topic rules... ruleEngine.AddRule( new PostTopicRegexReplaceRule( _RgxPost, @"<a href=""${post}"" title=""${inner}"">${inner}</a>", Options)); ruleEngine.AddRule( new PostTopicRegexReplaceRule( _RgxTopic, @"<a href=""${topic}"" title=""${inner}"">${inner}</a>", Options)); }