mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-04-19 22:08:34 -04:00
139 lines
3.1 KiB
C#
139 lines
3.1 KiB
C#
|
|
using Microsoft.AspNetCore.Components.Rendering;
|
|
|
|
/// <summary>
|
|
/// Takes a Html string and tries to turn it into a bunch of panels
|
|
/// </summary>
|
|
public class HtmlPanel : Panel
|
|
{
|
|
/// <summary>
|
|
/// The actual html value
|
|
/// </summary>
|
|
public string Html { get; set; }
|
|
|
|
protected override int BuildHash() => HashCode.Combine( Html );
|
|
|
|
protected override string GetRenderTreeChecksum() => $"{BuildHash()}";
|
|
|
|
protected override void BuildRenderTree( RenderTreeBuilder tree )
|
|
{
|
|
if ( string.IsNullOrWhiteSpace( Html ) )
|
|
return;
|
|
|
|
try
|
|
{
|
|
var node = Sandbox.Html.INode.Parse( Html );
|
|
|
|
int i = 0;
|
|
BuildRenderTree( tree, node, ref i );
|
|
FlushHtml( tree, node, ref i );
|
|
}
|
|
catch ( System.Exception e )
|
|
{
|
|
Log.Error( e );
|
|
}
|
|
}
|
|
|
|
static string[] breakinElements = ["div", "p", "h1", "h2", "h3", "h4", "figure", "pre", "img", "video", "blockquote", "ul", "li", "ol"];
|
|
|
|
static bool IsTextElement( Sandbox.Html.INode node )
|
|
{
|
|
if ( node.IsText ) return true;
|
|
if ( node.Name == "br" ) return true;
|
|
if ( node.Name == "strong" ) return true;
|
|
if ( node.Name == "spoiler" ) return true;
|
|
if ( node.Name == "a" ) return true;
|
|
if ( breakinElements.Contains( node.Name ) ) return false;
|
|
|
|
return node.Children.All( IsTextElement );
|
|
}
|
|
|
|
string html = "";
|
|
|
|
void FlushHtml( RenderTreeBuilder tree, Sandbox.Html.INode node, ref int index )
|
|
{
|
|
if ( string.IsNullOrWhiteSpace( html ) ) return;
|
|
|
|
tree.OpenElement<Label>( index++ );
|
|
tree.AddAttribute<Label>( index++, html, t => t.Text = html );
|
|
tree.AddAttribute<Label>( index++, true, t => t.IsRich = true );
|
|
tree.CloseElement();
|
|
|
|
html = "";
|
|
}
|
|
|
|
void BuildRenderTree( RenderTreeBuilder tree, Sandbox.Html.INode node, ref int index )
|
|
{
|
|
if ( node.IsComment )
|
|
return;
|
|
|
|
if ( IsTextElement( node ) )
|
|
{
|
|
html += node.OuterHtml;
|
|
return;
|
|
}
|
|
|
|
if ( node.Name == "figure" )
|
|
{
|
|
FlushHtml( tree, node, ref index );
|
|
ProcessFigure( tree, node, ref index );
|
|
return;
|
|
}
|
|
|
|
if ( node.Name == "img" )
|
|
{
|
|
FlushHtml( tree, node, ref index );
|
|
|
|
var src = node.GetAttribute( "src", "" );
|
|
tree.OpenElement<Image>( index++ );
|
|
tree.AddAttribute<Image>( index++, src, t => t.SetTexture( src ) );
|
|
tree.CloseElement();
|
|
return;
|
|
}
|
|
|
|
bool skipWrap = node.IsDocument;
|
|
|
|
if ( !skipWrap )
|
|
{
|
|
FlushHtml( tree, node, ref index );
|
|
tree.OpenElement( index++, node.Name );
|
|
// todo apply style attribute, class attribute?
|
|
// tree.AddContent( index++, $"<{node.Name}>" );
|
|
}
|
|
|
|
foreach ( var child in node.Children )
|
|
{
|
|
BuildRenderTree( tree, child, ref index );
|
|
}
|
|
|
|
if ( !skipWrap )
|
|
{
|
|
FlushHtml( tree, node, ref index );
|
|
|
|
// tree.AddContent( index++, $"</{node.Name}>" );
|
|
tree.CloseElement();
|
|
}
|
|
}
|
|
|
|
void ProcessFigure( RenderTreeBuilder tree, Sandbox.Html.INode node, ref int index )
|
|
{
|
|
if ( node.Name == "img" )
|
|
{
|
|
BuildRenderTree( tree, node, ref index );
|
|
return;
|
|
}
|
|
|
|
if ( node.Name == "figcaption" )
|
|
return;
|
|
|
|
//tree.AddContent( index++, $"<{node.Name}>" );
|
|
|
|
foreach ( var child in node.Children )
|
|
{
|
|
ProcessFigure( tree, child, ref index );
|
|
}
|
|
|
|
//tree.AddContent( index++, $"</{node.Name}>" );
|
|
}
|
|
}
|