152 lines
3.6 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
} |