emo-client/Saradomin/Utilities/HtmlRenderer.cs

152 lines
3.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Web;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Layout;
using Avalonia.Media;
using HtmlAgilityPack;
namespace Saradomin.Utilities
{
public class HtmlRenderer
{
private int _listDescent = 0;
private string _prefix;
private InlineCollection _inlines;
private HtmlNode _rootNode;
public HtmlRenderer(HtmlNode rootNode)
{
_rootNode = rootNode;
}
public InlineCollection Render()
{
_inlines = new();
{
Visit(_rootNode);
}
return _inlines;
}
private void InNewBlockDo(Action action)
{
action();
_inlines.Add(new LineBreak());
}
private void CreateNewInlineTextElement(
string text,
FontWeight weight = FontWeight.Normal,
double fontSize = 12
)
{
_inlines.Add(new Run(text)
{
FontWeight = weight,
FontSize = fontSize,
});
}
private void VisitBold(HtmlNode htmlNode)
{
CreateNewInlineTextElement(
HttpUtility.HtmlDecode(
htmlNode.GetDirectInnerText()
),
FontWeight.Bold
);
}
private void VisitList(HtmlNode htmlNode)
{
_listDescent++;
{
InNewBlockDo(() =>
{
foreach (var child in htmlNode.ChildNodes)
{
Visit(child);
}
});
}
_listDescent--;
}
private void VisitListEntry(HtmlNode htmlNode)
{
_inlines.Add(new Run("• "));
for (var i = 0; i < htmlNode.ChildNodes.Count; i++)
{
var child = htmlNode.ChildNodes[i];
if (i != 0)
{
_prefix = " ";
}
Visit(child);
_prefix = null;
}
_prefix = null;
_inlines.Add(new LineBreak());
}
private void VisitParagraph(HtmlNode htmlNode)
{
InNewBlockDo(() =>
{
foreach (var child in htmlNode.ChildNodes)
{
Visit(child);
}
});
}
private void Visit(HtmlNode htmlNode)
{
switch (htmlNode.Name)
{
case "#text":
var text = HttpUtility.HtmlDecode(
htmlNode.GetDirectInnerText().Trim(' ').Trim('\n')
);
CreateNewInlineTextElement($"{_prefix}{text}");
break;
case "br":
_inlines.Add(new LineBreak());
break;
case "b":
VisitBold(htmlNode);
break;
case "ul":
VisitList(htmlNode);
break;
case "li":
VisitListEntry(htmlNode);
break;
case "p":
VisitParagraph(htmlNode);
break;
default:
foreach (var child in htmlNode.ChildNodes)
{
Visit(child);
}
break;
}
}
}
}