kreta/Kreta.BusinessLogic/Logic/RichTextLogic.cs
2024-03-13 00:33:46 +01:00

231 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Web;
using HtmlAgilityPack;
using Kreta.BusinessLogic.Utils;
namespace Kreta.BusinessLogic.Logic
{
public static class RichTextLogic
{
public static List<string> LegalFastReportHtmlTagList = new List<string> { "br", "b", "i", "u", "sub", "sup" };
public static string[] RemovableHtmlTags = new string[] { "img" };
public static string CutHtmlTagsAndDecode(string input)
{
string result = HttpUtility.HtmlDecode(input);
result = Regex.Replace(result, "<.*?>", string.Empty);
return result;
}
public static string CutHtmlTagsAndDecodeAndBR2Space(string input)
{
if (!string.IsNullOrWhiteSpace(input))
{
string result = HttpUtility.HtmlDecode(input.Replace("<br>", " ").Replace("</br>", " "));
result = Regex.Replace(result, "<.*?>", string.Empty);
return result;
}
return input;
}
public static string RemoveSpecificHtmlTags(string input, string[] htmlTags)
{
if (string.IsNullOrWhiteSpace(input))
{
return input;
}
var inputHtml = HttpUtility.HtmlDecode(input);
foreach (var htmlTag in htmlTags)
{
inputHtml = Regex.Replace(inputHtml, $"<{htmlTag}" + @"([\w\W]+?)>", string.Empty);
}
return inputHtml;
}
public static string ConvertRawHtmlToRichTextHtml(string html)
{
var actions = new List<Action>();
void AddEscapeElementAction(HtmlNode node)
{
actions.Add(() => node.ParentNode.ReplaceChild(HtmlNode.CreateNode(WebUtility.HtmlEncode(node.OuterHtml)), node));
}
void AddRemovePropertyAction(HtmlNode node, HtmlAttribute attr)
{
actions.Add(() => node.Attributes.Remove(attr));
}
void CollectIllegalProperty(HtmlNode node)
{
var legalAttributes = new List<string> { "style", "href", "target" };
foreach (var item in node.Attributes)
{
if (!legalAttributes.Contains(item.Name))
{
AddRemovePropertyAction(node, item);
}
}
}
bool IsLegalItem(HtmlNode node)
{
var legalItems = new List<string> { "p", "span", "ul", "li", "strong", "del", "ol", "em", "#text", "div", "table", "colgroup", "tr", "td", "th", "tbody", "tfoot", "a", "form", "col", "thead", "head", "br", "strike", "h1", "h2", "h3", "h4", "h5", "h6" };
if (legalItems.Contains(node.Name))
{
CollectIllegalProperty(node);
return true;
}
AddEscapeElementAction(node);
return false;
}
void CheckChild(HtmlNode node)
{
if (node.HasChildNodes)
{
foreach (var childItem in node.ChildNodes)
{
if (IsLegalItem(childItem))
{
CheckChild(childItem);
}
}
}
}
var doc = new HtmlDocument();
doc.LoadHtml(WebUtility.HtmlDecode(html));
CheckChild(doc.DocumentNode);
foreach (var action in actions)
{
action.Invoke();
}
return doc.DocumentNode.InnerHtml;
}
public static string GetLegalHtmlString(string text, List<string> legalHtmlTagList, bool mustFastReportCompatible = false, bool enableHtmlTagProperties = false)
{
while (text.Contains("&amp;"))
{
text = text.Replace("&amp;", "&"); //NOTE: Replace-elni kell az "&amp;"-okat rekurzívan.
}
var result = text
.Replace("&lt;", "<") //NOTE: Replace-elni kell az "&lt;"-ket, ha valamiért a "<" encode-olva lenne.
.Replace("&gt;", ">") //NOTE: Replace-elni kell az "&gt;"-ket, ha valamiért a ">" encode-olva lenne.
.Replace("&nbsp;", "\u0020") //NOTE: Replace-elni kell az "&nbsp;"-ket.
.Replace("\u00A0", "\u0020"); //NOTE: Replace-elni kell a NO-BREAK SPACE-eket, mert a SPACE-el nem ekvivalens és jöhet be ilyen adat és okozhat problémát.
if (mustFastReportCompatible)
{
result = result
.Replace("<div><br></div>", "<br>") //NOTE: A külső div-be írt enter-et ezt generálják ki, ezt replace-eljük <br>-re.
.Replace("<p> </p>", "<br>") //NOTE: A kendo editor-ba írt enter-et ezt generálják ki, ezt replace-eljük <br>-re.
.Replace("<br />", "<br>") //NOTE: Az összes sortörést egységessé tesszük.
.Replace("<br/>", "<br>") //NOTE: Az összes sortörést egységessé tesszük.
.Replace("<div>", string.Empty) //NOTE: Az összes sortörést egységessé tesszük.
.Replace("</div>", "<br>") //NOTE: Az összes sortörést egységessé tesszük.
.Replace("<p>", string.Empty) //NOTE: Az összes sortörést egységessé tesszük.
.Replace("</p>", "<br>") //NOTE: Az összes sortörést egységessé tesszük.
.Replace("<strong>", "<b>") //NOTE: Egységes és FastReport kompatibilis tag-ekre replace-elünk.
.Replace("</strong>", "</b>") //NOTE: Egységes és FastReport kompatibilis tag-ekre replace-elünk.
.Replace("<em>", "<i>") //NOTE: Egységes és FastReport kompatibilis tag-ekre replace-elünk.
.Replace("</em>", "</i>") //NOTE: Egységes és FastReport kompatibilis tag-ekre replace-elünk.
.Replace("<span style=\"text-decoration:underline;\">", "<u>") //NOTE: Egységes és FastReport kompatibilis tag-ekre replace-elünk.
.Replace("</span>", "</u>"); //NOTE: Egységes és FastReport kompatibilis tag-ekre replace-elünk.
}
//NOTE: --- Start: Replace-eljük az összes nem legális html tag-et.
Random random = new Random();
//NOTE: Erre a bonyolult random-ozós replace-es logikára azért van szükség, hogy ne tudják hack-elni véletlenül sem a bejövő adatokat!
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
string closeTagTempString = $"¤{new string(Enumerable.Repeat(chars, 5).Select(s => s[random.Next(s.Length)]).ToArray())}¤";
string openTagTempString = $"÷{new string(Enumerable.Repeat(chars, 5).Select(s => s[random.Next(s.Length)]).ToArray())}÷";
//NOTE: Replace-eljük a legális html tag-eket, hogy azokat a RemoveAllHtmlTags, ne szedje ki!
foreach (var legalHtmlTag in legalHtmlTagList)
{
result = result.Replace($"</{legalHtmlTag}>", $"{closeTagTempString}{legalHtmlTag}{closeTagTempString}")
.Replace($"<{legalHtmlTag}>", $"{openTagTempString}{legalHtmlTag}{openTagTempString}");
//NOTE: Ha stílust tartalmaz a legalHtmlTag akkor azt nem szabad leszedni róla (pl szinezés miatt)
if (enableHtmlTagProperties)
{
result = result.Replace($"<{legalHtmlTag}", $"{openTagTempString}{legalHtmlTag}");
}
}
//NOTE: Replace-eljük az összes html tag-et, ami bennemaradt a szövegben.
result = CommonUtils.RemoveAllHtmlTags(result);
//NOTE: Vissza Replace-eljük a legális html tag-eket, hogy azok normális formában mentődjenek el!
foreach (var legalHtmlTag in legalHtmlTagList)
{
result = result.Replace($"{closeTagTempString}{legalHtmlTag}{closeTagTempString}", $"</{legalHtmlTag}>")
.Replace($"{openTagTempString}{legalHtmlTag}{openTagTempString}", $"<{legalHtmlTag}>");
//NOTE: Ha stílust tartalmaz a legalHtmlTag akkor azt nem szabad leszedni róla (pl szinezés miatt)
if (enableHtmlTagProperties)
{
result = result.Replace($"{openTagTempString}{legalHtmlTag}", $"<{legalHtmlTag}");
}
}
//NOTE: --- End: Replace-eljük az összes nem legális html tag-et.
//NOTE: Remove-oljuk a rossz lezáró tag-eket, amikhez nem tartozik nyitó tag!
HtmlDocument htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(result);
List<HtmlParseError> htmlParseErrorList = htmlDocument.ParseErrors.Where(x => x.Code == HtmlParseErrorCode.TagNotOpened).OrderByDescending(x => x.StreamPosition).ToList();
foreach (HtmlParseError htmlParseError in htmlParseErrorList)
{
result = result.Remove(htmlParseError.StreamPosition, htmlParseError.SourceText.Length);
}
return result;
}
/// INFO: Mobil használja
public static string RemoveHtmlForMobile(string text)
{
while (text.Contains("&amp;"))
{
text = text.Replace("&amp;", "&"); //NOTE: Replace-elni kell az "&amp;"-okat rekurzívan.
}
var result = text
.Replace("&lt;", "<") //NOTE: Replace-elni kell az "&lt;"-ket, ha valamiért a "<" encode-olva lenne.
.Replace("&gt;", ">") //NOTE: Replace-elni kell az "&gt;"-ket, ha valamiért a ">" encode-olva lenne.
.Replace("&nbsp;", "\u0020") //NOTE: Replace-elni kell az "&nbsp;"-ket.
.Replace("\u00A0", "\u0020") //NOTE: Replace-elni kell a NO-BREAK SPACE-eket, mert a SPACE-el nem ekvivalens és jöhet be ilyen adat és okozhat problémát.
.Replace("<div><br></div>", " ") //NOTE: A külső div-be írt enter-et ezt generálják ki, ezt replace-eljük szóközre.
.Replace("<p> </p>", " ") //NOTE: A kendo editor-ba írt enter-et ezt generálják ki, ezt replace-eljük szóközre.
.Replace("<br />", " ") //NOTE: Az összes sortörést szóközre cseréljük.
.Replace("<br/>", " ") //NOTE: Az összes sortörést szóközre cseréljük.
.Replace("<br>", " ") //NOTE: Az összes sortörést szóközre cseréljük.
.Replace("</div>", " ") //NOTE: Az összes sortörést szóközre cseréljük.
.Replace("</p>", " ") //NOTE: Az összes sortörést szóközre cseréljük.
.Replace("<div>", string.Empty) //NOTE: Az összes sortörést szóközre cseréljük.
.Replace("<p>", string.Empty) //NOTE: Az összes sortörést szóközre cseréljük.
.Replace("</li>", " ") //NOTE: A felsorolás elemeit is elválasztjuk.
.Replace("<strong>", string.Empty) //NOTE: A formázás tageket töröljük.
.Replace("</strong>", string.Empty) //NOTE: A formázás tageket töröljük.
.Replace("<em>", string.Empty) //NOTE: A formázás tageket töröljük.
.Replace("</em>", string.Empty) //NOTE: A formázás tageket töröljük.
.Replace("<span style=\"text-decoration:underline;\">", string.Empty) //NOTE: A formázás tageket töröljük.
.Replace("</span>", string.Empty); //NOTE: A formázás tageket töröljük.
result = CommonUtils.RemoveAllHtmlTags(result);
return HttpUtility.HtmlDecode(result);
}
}
}