string ParseNode(BBCodeNode node, BBCode code = null) { // Text only nodes doesn't need any parsing if (string.IsNullOrEmpty(node.TagName)) { string innerHtml = ParseNewLines(node.InnerContent); return(innerHtml); } if (code == null) { code = GetBBCodeForNode(node); } if (code == null) { string innerHtml = node.OpenTag; // If we find unknown bbcodes, try parsing their inner content html and display the raw outer bbcode so that the user know it's not parseable. if (node.Childs != null) { node.Childs.ForEach(childNode => innerHtml += ParseNode(childNode)); } else { // We also end up here if square brackets were used in other ways like quote, which shouldnt got destroyed: "He [mr xyz] said that..." // In this case, InnerContent is the content after the brackets and childs may be null. No childs exists. innerHtml += ParseNewLines(node.InnerContent); } // ParseNewLines() call is exceptional here. Regularly it's handled by GetNodeInnerContentHtml() return(innerHtml + node.CloseTag); } string html = ""; if (code.ParserFunc != null) { // From a parser function, we expect to handle the ENTIRE node. Only for this reason, the inner html is required and only provided here node.InnerHtml = GetNodeInnerContentHtml(node, code.NestedChild); html = code.ParserFunc(node); } else { string openTag = code.HtmlTag; if (!string.IsNullOrEmpty(code.ArgumentHtmlAttribute)) { // When theres no custom display text (e.g. [url]https://ecosia.org[/url]) we set the argument like in [url=https://ecosia.org]https://ecosia.org[/url] to have a unified link target if (code.BBCodeName == "url" && node.Argument == null) { node.Argument = node.InnerContent; } openTag = openTag.Replace(">", $" {code.ArgumentHtmlAttribute}=\"{node.Argument}\">"); } string closeTag = code.HtmlTag.Replace("<", "</"); html += openTag + GetNodeInnerContentHtml(node, code.NestedChild) + closeTag; } return(html); }