@using AngleSharp
@using Dpz.Core.EnumLibrary
@using Ganss.Xss
@using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration
@model IPagedList<Dpz.Core.Public.ViewModel.Response.MumbleResponse>
@inject IConfiguration Configuration
@{
var rule = Configuration.GetSection("XSS").Get<CrossSiteRule>();
var sanitizer = rule?.CustomHtmlSanitizer() ?? new HtmlSanitizer();
var context = BrowsingContext.New(AngleSharp.Configuration.Default);
async Task<string> ProcessContentAsync(string html)
{
var document = await context.OpenAsync(y => y.Content(html));
// Process Links
var links = document.GetElementsByTagName("a");
foreach (var link in links)
{
var href = link.GetAttribute("href");
if (href != null && !href.StartsWith("javascript", StringComparison.CurrentCultureIgnoreCase))
{
link.SetAttribute("target", "_blank");
link.SetAttribute("rel", "noopener noreferrer");
}
}
// Process Images
var images = document.GetElementsByTagName("img");
foreach (var img in images)
{
var src = img.GetAttribute("src");
// Use native lazy loading, but keep src valid
if (string.IsNullOrEmpty(src))
{
img.SetAttribute("src", $"{Program.AssetsHost}/images/notfound.png");
}
img.SetAttribute("loading", "lazy");
}
return sanitizer.Sanitize(document.Body?.InnerHtml ?? "");
}
}
@foreach (var item in Model)
{
<article class="mumble-card" id="mumble-@item.Id">
<div class="mumble-card__header">
<img class="mumble-card__avatar" src="@item.Author.Avatar" alt="@item.Author.Name" loading="lazy">
<div class="mumble-card__meta">
<div class="mumble-card__author">
@item.Author.Name
<span class="mumble-card__role">@(item.Author.Permissions?.HasFlag(Permissions.System) == true ? "管理员" : "成员")</span>
</div>
<time class="mumble-card__time timeago" datetime="@item.CreateTime">@item.CreateTime</time>
</div>
</div>
<div class="mumble-card__content markdown-body">
@Html.Raw(await ProcessContentAsync(item.Markdown.MarkdownToHtml(false)))
</div>
<div class="mumble-card__footer">
<a href="@Url.Action("Comment", "Mumble", new { id = item.Id })" class="mumble-action" title="详情" data-pjax>
<i class="fa fa-info-circle"></i>
<span>详情</span>
</a>
<button class="mumble-action" data-comment-toggle="@item.Id" title="评论">
<i class="fa fa-commenting"></i>
<span data-comment-count>@item.CommentCount</span>
</button>
<button class="mumble-action" data-like-id="@item.Id" title="点赞">
<i class="fa fa-thumbs-up"></i>
<span data-like-count>@item.Like</span>
</button>
</div>
<!-- Comments Container -->
<div class="mumble-comments is-hidden"
id="comments-@item.Id"
data-load-url="@Url.Action("Index", "Comment", new { node = CommentNode.Mumble, relation = item.Id })">
<!-- Content loaded via JS -->
<div class="text-center text-muted p-3">
<i class="fa fa-spinner fa-spin"></i> 加载评论中...
</div>
</div>
</article>
} 评论加载中...