using System.Reflection; using System.Text; using NTDLS.Helpers; using ZelWiki.Engine.Function; using ZelWiki.Engine.Implementation.Utility; using ZelWiki.Engine.Library; using ZelWiki.Engine.Library.Interfaces; using ZelWiki.Library; using ZelWiki.Models; using ZelWiki.Models.DataModels; using ZelWiki.Repository; using Constants = ZelWiki.Engine.Library.Constants; namespace ZelWiki.Engine.Implementation { /// /// 处理函数调用. /// public class StandardFunctionHandler : IStandardFunctionHandler { private static FunctionPrototypeCollection? _collection; public FunctionPrototypeCollection Prototypes { get { if (_collection == null) { _collection = new FunctionPrototypeCollection(FunctionPrototypeCollection.WikiFunctionType.Standard); #region _collection.Add("##Snippet: [name]"); _collection.Add("##Seq: {key}='Default'"); _collection.Add("##Set: [key] | [value]"); _collection.Add("##Get: [key]"); _collection.Add("##Color: [color] | [text]"); _collection.Add("##Tag: [pageTags]"); _collection.Add( "##SearchList: [searchPhrase] | {styleName(List,Full)}='Full' | {pageSize}='5' | {pageSelector}='true' | {allowFuzzyMatching}='false' | {showNamespace}='false'"); _collection.Add( "##TagList: [pageTags] | {Top}='1000' | {styleName(List,Full)}='Full' | {showNamespace}='false'"); _collection.Add( "##NamespaceGlossary: [namespaces] | {Top}='1000' | {styleName(List,Full)}='Full' | {showNamespace}='false'"); _collection.Add( "##NamespaceList: [namespaces] | {Top}='1000' | {styleName(List,Full)}='Full' | {showNamespace}='false'"); _collection.Add( "##TagGlossary: [pageTags] | {Top}='1000' | {styleName(List,Full)}='Full' | {showNamespace}='false'"); _collection.Add( "##RecentlyModified: {Top}='1000' | {styleName(List,Full)}='Full' | {showNamespace}='false'"); _collection.Add( "##TextGlossary: [searchPhrase] | {Top}='1000' | {styleName(List,Full)}='Full' | {showNamespace}='false'"); _collection.Add("##Image: [name] | {scale}='100' | {altText}=''"); _collection.Add("##File: [name] | {linkText} | {showSize}='false'"); _collection.Add( "##Related: {styleName(List,Flat,Full)}='Full' | {pageSize}='10' | {pageSelector}='true'"); _collection.Add( "##Similar: {similarity}='80' | {styleName(List,Flat,Full)}='Full' | {pageSize}='10' | {pageSelector}='true'"); _collection.Add("##EditLink: {linkText}='edit'"); _collection.Add("##Inject: [pageName]"); _collection.Add("##Include: [pageName]"); _collection.Add("##BR: {Count}='1'"); _collection.Add("##HR: {Height}='1'"); _collection.Add( "##Revisions:{styleName(Full,List)}='Full' | {pageSize}='5' | {pageSelector}='true' | {pageName}=''"); _collection.Add( "##Attachments:{styleName(Full,List)}='Full' | {pageSize}='5' | {pageSelector}='true' | {pageName}=''"); _collection.Add("##Title:"); _collection.Add("##Navigation:"); _collection.Add("##Name:"); _collection.Add("##SiteName:"); _collection.Add("##Namespace:"); _collection.Add("##Created:"); _collection.Add("##LastModified:"); _collection.Add("##AppVersion:"); _collection.Add( "##ProfileGlossary: {Top}='1000' | {pageSize}='100' | {searchToken}=''"); _collection.Add( "##ProfileList: {Top}='1000' | {pageSize}='100' | {searchToken}=''"); _collection.Add("##SystemEmojiCategoryList:"); _collection.Add("##SystemEmojiList:"); #endregion } return _collection; } } private static Page? GetPageFromPathInfo(string routeData) { routeData = NamespaceNavigation.CleanAndValidate(routeData); var page = PageRepository.GetPageRevisionByNavigation(routeData); return page; } private static void MergeUserVariables(ref IZelEngineState state, Dictionary items) { foreach (var item in items) { state.Variables[item.Key] = item.Value; } } private static void MergeSnippets(ref IZelEngineState state, Dictionary items) { foreach (var item in items) { state.Snippets[item.Key] = item.Value; } } /// /// 当匹配到合适的原型时,调用它来处理函数调用。 /// /// /// /// /// /// public HandlerResult Handle(IZelEngineState state, FunctionCall function, string? scopeBody = null) { switch (function.Name.ToLower()) { case "profileglossary": { if (!GlobalConfiguration.EnablePublicProfiles) { return new HandlerResult("公共配置文件已禁用."); } var html = new StringBuilder(); var refTag = state.GetNextQueryToken(); var pageNumber = int.Parse(state.QueryString[refTag].ToString().DefaultWhenNullOrEmpty("1")); var pageSize = function.Parameters.Get("pageSize"); var searchToken = function.Parameters.Get("searchToken"); var topCount = function.Parameters.Get("top"); var profiles = UsersRepository.GetAllPublicProfilesPaged(pageNumber, pageSize, searchToken); var glossaryName = "glossary_" + new Random().Next(0, 1000000).ToString(); var alphabet = profiles.Select(p => p.AccountName.Substring(0, 1).ToUpper()).Distinct(); if (profiles.Any()) { html.Append("
"); foreach (var alpha in alphabet) { html.Append("" + alpha + " "); } html.Append("
"); html.Append("
    "); foreach (var alpha in alphabet) { html.Append("
  • " + alpha + "
  • "); html.Append("
      "); foreach (var profile in profiles.Where(p => p.AccountName.ToLower().StartsWith(alpha.ToLower()))) { html.Append( $"
    • {profile.AccountName}"); html.Append("
    • "); } html.Append("
    "); } html.Append("
"); } return new HandlerResult(html.ToString()); } case "profilelist": { if (!GlobalConfiguration.EnablePublicProfiles) { return new HandlerResult("公共配置文件已禁用."); } var html = new StringBuilder(); var refTag = state.GetNextQueryToken(); var pageNumber = int.Parse(state.QueryString[refTag].ToString().DefaultWhenNullOrEmpty("1")); var pageSize = function.Parameters.Get("pageSize"); var searchToken = function.Parameters.Get("searchToken"); var profiles = UsersRepository.GetAllPublicProfilesPaged(pageNumber, pageSize, searchToken); if (profiles.Any()) { html.Append("
    "); foreach (var profile in profiles) { html.Append( $"
  • {profile.AccountName}"); html.Append("
  • "); } html.Append("
"); } if (profiles.Count > 0 && profiles.First().PaginationPageCount > 1) { html.Append(PageSelectorGenerator.Generate(refTag, state.QueryString, profiles.First().PaginationPageCount)); } return new HandlerResult(html.ToString()); } case "attachments": { var refTag = state.GetNextQueryToken(); var pageNumber = int.Parse(state.QueryString[refTag].ToString().DefaultWhenNullOrEmpty("1")); var navigation = NamespaceNavigation.CleanAndValidate(function.Parameters.Get("pageName", state.Page.Navigation)); var styleName = function.Parameters.Get("styleName").ToLower(); var pageSize = function.Parameters.Get("pageSize"); var pageSelector = function.Parameters.Get("pageSelector"); var attachments = PageFileRepository.GetPageFilesInfoByPageNavigationAndPageRevisionPaged(navigation, pageNumber, pageSize, state.Revision); var html = new StringBuilder(); if (attachments.Count > 0) { html.Append("
    "); foreach (var file in attachments) { if (state.Revision != null) { html.Append( $"
  • {file.Name}"); } else { html.Append( $"
  • {file.Name} "); } if (styleName == "full") { html.Append($" - ({file.FriendlySize})"); } html.Append("
  • "); } html.Append("
"); if (pageSelector && attachments.Count > 0 && attachments.First().PaginationPageCount > 1) { html.Append(PageSelectorGenerator.Generate(refTag, state.QueryString, attachments.First().PaginationPageCount)); } } return new HandlerResult(html.ToString()); } case "revisions": { if (state.Session == null) { throw new Exception($"session异常."); } var refTag = state.GetNextQueryToken(); var pageNumber = int.Parse(state.QueryString[refTag].ToString().DefaultWhenNullOrEmpty("1")); var navigation = NamespaceNavigation.CleanAndValidate(function.Parameters.Get("pageName", state.Page.Navigation)); var styleName = function.Parameters.Get("styleName").ToLower(); var pageSize = function.Parameters.Get("pageSize"); var pageSelector = function.Parameters.Get("pageSelector"); var revisions = PageRepository.GetPageRevisionsInfoByNavigationPaged(navigation, pageNumber, null, null, pageSize); var html = new StringBuilder(); if (revisions.Any()) { html.Append("
    "); foreach (var item in revisions) { html.Append( $"
  • {item.Revision} by {item.ModifiedByUserName} on {state.Session.LocalizeDateTime(item.ModifiedDate)}"); if (styleName == "full") { var thisRev = PageRepository.GetPageRevisionByNavigation(state.Page.Navigation, item.Revision); var prevRev = PageRepository.GetPageRevisionByNavigation(state.Page.Navigation, item.Revision - 1); var summaryText = Differentiator.GetComparisonSummary(thisRev?.Body ?? string.Empty, prevRev?.Body ?? string.Empty); if (summaryText.Length > 0) { html.Append(" - " + summaryText); } } html.Append("
  • "); } html.Append("
"); if (pageSelector && revisions.Count > 0 && revisions.First().PaginationPageCount > 1) { html.Append(PageSelectorGenerator.Generate(refTag, state.QueryString, revisions.First().PaginationPageCount)); } } return new HandlerResult(html.ToString()); } case "seq": //##Seq({Key}) 在文档中插入序列. { var key = function.Parameters.Get("Key"); var sequences = state.GetStateValue("_sequences", new Dictionary()); if (sequences.ContainsKey(key) == false) { sequences.Add(key, 0); } sequences[key]++; return new HandlerResult(sequences[key].ToString()) { Instructions = [Constants.HandlerResultInstruction.OnlyReplaceFirstMatch] }; } case "editlink": //(##EditLink(link text)) { var linkText = function.Parameters.Get("linkText"); return new HandlerResult($"{linkText}"); } case "inject": //(PageName) { var navigation = function.Parameters.Get("pageName"); var page = GetPageFromPathInfo(navigation); if (page != null) { return new HandlerResult(page.Body) { Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine] }; } throw new Exception($"未找到包含页面: [{navigation}]"); } case "include": //(PageName) { var navigation = function.Parameters.Get("pageName"); var page = GetPageFromPathInfo(navigation); if (page != null) { var childState = state.TransformChild(page); MergeUserVariables(ref state, childState.Variables); MergeSnippets(ref state, childState.Snippets); return new HandlerResult(childState.HtmlResult) { Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine] }; } throw new Exception($"T未找到包含页面: [{navigation}]"); } case "set": { var key = function.Parameters.Get("key"); var value = function.Parameters.Get("value"); if (state.Variables.ContainsKey(key)) { state.Variables[key] = value; } else { state.Variables.Add(key, value); } return new HandlerResult(string.Empty) { Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine] }; } case "get": { var key = function.Parameters.Get("key"); if (state.Variables.TryGetValue(key, out var variable)) { return new HandlerResult(variable); } throw new Exception( $"未定义变量 {key} .需要在调用Get()前设置##Set()."); } case "color": { var color = function.Parameters.Get("color"); var text = function.Parameters.Get("text"); return new HandlerResult($"{text}"); } case "tag": //##tag(pipe|separated|list|of|tags) { var tags = function.Parameters.GetList("pageTags"); state.Tags.AddRange(tags); state.Tags = state.Tags.Distinct().ToList(); return new HandlerResult(string.Empty) { Instructions = [Constants.HandlerResultInstruction.TruncateTrailingLine] }; } case "image": //##Image(Name, [optional:default=100]Scale, [optional:default=""]Alt-Text) { var imageName = function.Parameters.Get("name"); var alt = function.Parameters.Get("alttext", imageName); var scale = function.Parameters.Get("scale"); var explicitNamespace = imageName.Contains("::"); var isPageForeignImage = false; var navigation = state.Page.Navigation; if (imageName.StartsWith("http", StringComparison.InvariantCultureIgnoreCase)) { string image = $"\"{alt}\""; return new HandlerResult(image); } else if (imageName.Contains('/')) { //允许从其他页面加载附加图像. var slashIndex = imageName.IndexOf("/"); navigation = NamespaceNavigation.CleanAndValidate(imageName.Substring(0, slashIndex)); imageName = imageName.Substring(slashIndex + 1); isPageForeignImage = true; } if (explicitNamespace == false && state.Page.Namespace != null) { if (PageFileRepository.GetPageFileAttachmentInfoByPageNavigationPageRevisionAndFileNavigation( navigation, NamespaceNavigation.CleanAndValidate(imageName), state.Revision) == null) { //如果图像不存在,也没有指定命名空间,但页面有命名空间,则默认为页面命名空间. navigation = NamespaceNavigation.CleanAndValidate($"{state.Page.Namespace}::{imageName}"); } } if (state.Revision != null && isPageForeignImage == false) { var link = $"/Page/Image/{navigation}/{NamespaceNavigation.CleanAndValidate(imageName)}/{state.Revision}"; var image = $"\"{alt}\""; return new HandlerResult(image); } else { var link = $"/Page/Image/{navigation}/{NamespaceNavigation.CleanAndValidate(imageName)}"; var image = $"\"{alt}\""; return new HandlerResult(image); } } //显示文件下载链接 case "file": //##file(Name | Alt-Text | [optional display file size] true/false) { var fileName = function.Parameters.Get("name"); var explicitNamespace = fileName.Contains("::"); var isPageForeignFile = false; var navigation = state.Page.Navigation; if (fileName.Contains('/')) { //允许从其他页面加载附加图像。 var slashIndex = fileName.IndexOf("/"); navigation = NamespaceNavigation.CleanAndValidate(fileName.Substring(0, slashIndex)); fileName = fileName.Substring(slashIndex + 1); isPageForeignFile = true; } if (explicitNamespace == false && state.Page.Namespace != null) { if (PageFileRepository.GetPageFileAttachmentInfoByPageNavigationPageRevisionAndFileNavigation( navigation, NamespaceNavigation.CleanAndValidate(fileName), state.Revision) == null) { navigation = NamespaceNavigation.CleanAndValidate($"{state.Page.Namespace}::{fileName}"); } } var attachment = PageFileRepository.GetPageFileAttachmentInfoByPageNavigationPageRevisionAndFileNavigation( navigation, NamespaceNavigation.CleanAndValidate(fileName), state.Revision); if (attachment != null) { var alt = function.Parameters.Get("linkText", fileName); if (function.Parameters.Get("showSize")) { alt += $" ({attachment.FriendlySize})"; } if (state.Revision != null && isPageForeignFile == false) { var link = $"/Page/Binary/{navigation}/{NamespaceNavigation.CleanAndValidate(fileName)}/{state.Revision}"; var image = $"{alt}"; return new HandlerResult(image); } else { var link = $"/Page/Binary/{navigation}/{NamespaceNavigation.CleanAndValidate(fileName)}"; var image = $"{alt}"; return new HandlerResult(image); } } throw new Exception($"File not found [{fileName}]"); } case "recentlymodified": //##RecentlyModified(TopCount) { var styleName = function.Parameters.Get("styleName").ToLower(); var takeCount = function.Parameters.Get("top"); var showNamespace = function.Parameters.Get("showNamespace"); var pages = PageRepository.GetTopRecentlyModifiedPagesInfo(takeCount) .OrderByDescending(o => o.ModifiedDate).ThenBy(o => o.Title).ToList(); var html = new StringBuilder(); if (pages.Any()) { html.Append("
    "); foreach (var page in pages) { if (showNamespace) { html.Append( $"
  • {page.Name}"); } else { html.Append( $"
  • {page.Title}"); } if (styleName == "full") { if (page?.Description?.Length > 0) { html.Append(" - " + page.Description); } } html.Append("
  • "); } html.Append("
"); } return new HandlerResult(html.ToString()); } case "namespaceglossary": { var glossaryName = "glossary_" + new Random().Next(0, 1000000).ToString(); var namespaces = function.Parameters.GetList("namespaces"); var styleName = function.Parameters.Get("styleName").ToLower(); var topCount = function.Parameters.Get("top"); var pages = PageRepository.GetPageInfoByNamespaces(namespaces).Take(topCount).OrderBy(o => o.Name) .ToList(); var html = new StringBuilder(); var alphabet = pages.Select(p => p.Title.Substring(0, 1).ToUpper()).Distinct(); var showNamespace = function.Parameters.Get("showNamespace"); if (pages.Any()) { html.Append("
"); foreach (var alpha in alphabet) { html.Append("" + alpha + " "); } html.Append("
"); html.Append("
    "); foreach (var alpha in alphabet) { html.Append("
  • " + alpha + "
  • "); html.Append("
      "); foreach (var page in pages.Where(p => p.Title.ToLower().StartsWith(alpha.ToLower()))) { if (showNamespace) { html.Append( $"
    • {page.Name}"); } else { html.Append( $"
    • {page.Title}"); } if (styleName == "full") { if (page?.Description?.Length > 0) { html.Append(" - " + page.Description); } } html.Append("
    • "); } html.Append("
    "); } html.Append("
"); } return new HandlerResult(html.ToString()); } case "namespacelist": { var styleName = function.Parameters.Get("styleName").ToLower(); var topCount = function.Parameters.Get("top"); var namespaces = function.Parameters.GetList("namespaces"); var showNamespace = function.Parameters.Get("showNamespace"); var pages = PageRepository.GetPageInfoByNamespaces(namespaces).Take(topCount).OrderBy(o => o.Name) .ToList(); var html = new StringBuilder(); if (pages.Any()) { html.Append("
    "); foreach (var page in pages) { if (showNamespace) { html.Append( $"
  • {page.Name}"); } else { html.Append( $"
  • {page.Title}"); } if (styleName == "full") { if (page?.Description?.Length > 0) { html.Append(" - " + page.Description); } } html.Append("
  • "); } html.Append("
"); } return new HandlerResult(html.ToString()); } case "tagglossary": { var glossaryName = "glossary_" + new Random().Next(0, 1000000).ToString(); var tags = function.Parameters.GetList("pageTags"); var styleName = function.Parameters.Get("styleName").ToLower(); var topCount = function.Parameters.Get("top"); var pages = PageRepository.GetPageInfoByTags(tags).Take(topCount).OrderBy(o => o.Name).ToList(); var html = new StringBuilder(); var alphabet = pages.Select(p => p.Title.Substring(0, 1).ToUpper()).Distinct(); var showNamespace = function.Parameters.Get("showNamespace"); if (pages.Any()) { html.Append("
"); foreach (var alpha in alphabet) { html.Append("" + alpha + " "); } html.Append("
"); html.Append("
    "); foreach (var alpha in alphabet) { html.Append("
  • " + alpha + "
  • "); html.Append("
      "); foreach (var page in pages.Where(p => p.Title.ToLower().StartsWith(alpha.ToLower()))) { if (showNamespace) { html.Append( $"
    • {page.Name}"); } else { html.Append( $"
    • {page.Title}"); } if (styleName == "full") { if (page?.Description?.Length > 0) { html.Append(" - " + page.Description); } } html.Append("
    • "); } html.Append("
    "); } html.Append("
"); } return new HandlerResult(html.ToString()); } case "textglossary": { var glossaryName = "glossary_" + new Random().Next(0, 1000000).ToString(); var searchTokens = function.Parameters.Get("searchPhrase") .Split(" ", StringSplitOptions.RemoveEmptyEntries).ToList(); var topCount = function.Parameters.Get("top"); var showNamespace = function.Parameters.Get("showNamespace"); var pages = PageRepository.PageSearch(searchTokens).Take(topCount).OrderBy(o => o.Name).ToList(); var html = new StringBuilder(); var alphabet = pages.Select(p => p.Title.Substring(0, 1).ToUpper()).Distinct(); var styleName = function.Parameters.Get("styleName").ToLower(); if (pages.Count() > 0) { html.Append("
"); foreach (var alpha in alphabet) { html.Append("" + alpha + " "); } html.Append("
"); html.Append("
    "); foreach (var alpha in alphabet) { html.Append("
  • " + alpha + "
  • "); html.Append("
      "); foreach (var page in pages.Where(p => p.Title.ToLower().StartsWith(alpha.ToLower()))) { if (showNamespace) { html.Append( $"
    • {page.Name}"); } else { html.Append( $"
    • {page.Title}"); } if (styleName == "full") { if (page?.Description?.Length > 0) { html.Append(" - " + page.Description); } } html.Append("
    • "); } html.Append("
    "); } html.Append("
"); } return new HandlerResult(html.ToString()); } case "searchlist": { var styleName = function.Parameters.Get("styleName").ToLower(); var refTag = state.GetNextQueryToken(); var pageNumber = int.Parse(state.QueryString[refTag].ToString().DefaultWhenNullOrEmpty("1")); var pageSize = function.Parameters.Get("pageSize"); var pageSelector = function.Parameters.Get("pageSelector"); var allowFuzzyMatching = function.Parameters.Get("allowFuzzyMatching"); var searchTokens = function.Parameters.Get("searchPhrase") .Split(" ", StringSplitOptions.RemoveEmptyEntries).ToList(); var showNamespace = function.Parameters.Get("showNamespace"); var pages = PageRepository.PageSearchPaged(searchTokens, pageNumber, pageSize, allowFuzzyMatching); var html = new StringBuilder(); if (pages.Any()) { html.Append("
    "); foreach (var page in pages) { if (showNamespace) { html.Append( $"
  • {page.Name}"); } else { html.Append( $"
  • {page.Title}"); } if (styleName == "full") { if (page?.Description?.Length > 0) { html.Append(" - " + page.Description); } } html.Append("
  • "); } html.Append("
"); } if (pageSelector && (pageNumber > 1 || (pages.Count > 0 && pages.First().PaginationPageCount > 1))) { html.Append(PageSelectorGenerator.Generate(refTag, state.QueryString, pages.FirstOrDefault()?.PaginationPageCount ?? 1)); } return new HandlerResult(html.ToString()); } case "taglist": { var styleName = function.Parameters.Get("styleName").ToLower(); var topCount = function.Parameters.Get("top"); var tags = function.Parameters.GetList("pageTags"); var showNamespace = function.Parameters.Get("showNamespace"); var pages = PageRepository.GetPageInfoByTags(tags).Take(topCount).OrderBy(o => o.Name).ToList(); var html = new StringBuilder(); if (pages.Any()) { html.Append("
    "); foreach (var page in pages) { if (showNamespace) { html.Append( $"
  • {page.Name}"); } else { html.Append( $"
  • {page.Title}"); } if (styleName == "full") { if (page?.Description?.Length > 0) { html.Append(" - " + page.Description); } } html.Append("
  • "); } html.Append("
"); } return new HandlerResult(html.ToString()); } case "similar": //##Similar() { var refTag = state.GetNextQueryToken(); var similarity = function.Parameters.Get("similarity"); var pageNumber = int.Parse(state.QueryString[refTag].ToString().DefaultWhenNullOrEmpty("1")); var pageSize = function.Parameters.Get("pageSize"); var pageSelector = function.Parameters.Get("pageSelector"); var styleName = function.Parameters.Get("styleName").ToLower(); var html = new StringBuilder(); var pages = PageRepository.GetSimilarPagesPaged(state.Page.Id, similarity, pageNumber, pageSize); if (styleName == "list") { html.Append("
    "); foreach (var page in pages) { html.Append( $"
  • {page.Title}"); } html.Append("
"); } else if (styleName == "flat") { foreach (var page in pages) { if (html.Length > 0) html.Append(" | "); html.Append( $"{page.Title}"); } } else if (styleName == "full") { html.Append("
    "); foreach (var page in pages) { html.Append( $"
  • {page.Title} - {page.Description}"); } html.Append("
"); } if (pageSelector && pages.Count > 0 && pages.First().PaginationPageCount > 1) { html.Append(PageSelectorGenerator.Generate(refTag, state.QueryString, pages.First().PaginationPageCount)); } return new HandlerResult(html.ToString()); } case "related": //##related { var refTag = state.GetNextQueryToken(); var pageNumber = int.Parse(state.QueryString[refTag].ToString().DefaultWhenNullOrEmpty("1")); var pageSize = function.Parameters.Get("pageSize"); var pageSelector = function.Parameters.Get("pageSelector"); var styleName = function.Parameters.Get("styleName").ToLower(); var html = new StringBuilder(); var pages = PageRepository.GetRelatedPagesPaged(state.Page.Id, pageNumber, pageSize); if (styleName == "list") { html.Append("
    "); foreach (var page in pages) { html.Append( $"
  • {page.Title}"); } html.Append("
"); } else if (styleName == "flat") { foreach (var page in pages) { if (html.Length > 0) html.Append(" | "); html.Append( $"{page.Title}"); } } else if (styleName == "full") { html.Append("
    "); foreach (var page in pages) { html.Append( $"
  • {page.Title} - {page.Description}"); } html.Append("
"); } if (pageSelector && pages.Count > 0 && pages.First().PaginationPageCount > 1) { html.Append(PageSelectorGenerator.Generate(refTag, state.QueryString, pages.First().PaginationPageCount)); } return new HandlerResult(html.ToString()); } case "lastmodified": { if (state.Session == null) { throw new Exception($"Session异常."); } if (state.Page.ModifiedDate != DateTime.MinValue) { var localized = state.Session.LocalizeDateTime(state.Page.ModifiedDate); return new HandlerResult($"{localized.ToShortDateString()} {localized.ToShortTimeString()}"); } return new HandlerResult(string.Empty); } case "created": { if (state.Session == null) { throw new Exception($"Session异常."); } if (state.Page.CreatedDate != DateTime.MinValue) { var localized = state.Session.LocalizeDateTime(state.Page.CreatedDate); return new HandlerResult($"{localized.ToShortDateString()} {localized.ToShortTimeString()}"); } return new HandlerResult(string.Empty); } case "appversion": { var version = string.Join('.', (Assembly.GetExecutingAssembly() .GetName().Version?.ToString() ?? "0.0.0.0").Split('.').Take(3)); //Major.Minor.Patch return new HandlerResult(version); } case "name": { return new HandlerResult(state.Page.Title); } case "sitename": { return new HandlerResult(GlobalConfiguration.Name); } case "title": { return new HandlerResult($"

{state.Page.Title}

"); } case "namespace": { return new HandlerResult(state.Page.Namespace ?? string.Empty); } case "snippet": { var name = function.Parameters.Get("name"); return state.Snippets.ContainsKey(name) ? new HandlerResult(state.Snippets[name]) : new HandlerResult(string.Empty); } case "br": case "nl": case "newline": //##NewLine([optional:default=1]count) { var lineBreaks = new StringBuilder(); var count = function.Parameters.Get("Count"); for (var i = 0; i < count; i++) { lineBreaks.Append("
"); } return new HandlerResult(lineBreaks.ToString()); } case "hr": { var size = function.Parameters.Get("height"); return new HandlerResult($"
"); } case "navigation": { return new HandlerResult(state.Page.Navigation); } case "systememojilist": { StringBuilder html = new(); html.Append($""); html.Append($""); html.Append($""); html.Append($""); html.Append($""); html.Append($""); html.Append($""); html.Append($""); var category = state.QueryString["Category"].ToString(); html.Append($""); if (string.IsNullOrWhiteSpace(category) == false) { var emojis = EmojiRepository.GetEmojisByCategory(category); foreach (var emoji in emojis) { html.Append($""); html.Append($""); //html.Append($""); html.Append( $""); html.Append($""); html.Append($""); } } html.Append($""); html.Append($"
NameImageShortcut
{emoji.Name}{emoji.Shortcut}
"); return new HandlerResult(html.ToString()) { Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing] }; } case "systememojicategorylist": { var categories = EmojiRepository.GetEmojiCategoriesGrouped(); StringBuilder html = new(); html.Append($""); var rowNumber = 0; html.Append($""); html.Append($""); html.Append($""); html.Append($""); html.Append($""); html.Append($""); foreach (var category in categories) { if (rowNumber == 1) { html.Append($""); } html.Append($""); html.Append( $""); html.Append($""); html.Append($""); rowNumber++; } html.Append($""); html.Append($"
NameCount of Emojis
{category.Category}{category.EmojiCount:N0}
"); return new HandlerResult(html.ToString()) { Instructions = [Constants.HandlerResultInstruction.DisallowNestedProcessing] }; } } return new HandlerResult() { Instructions = [Constants.HandlerResultInstruction.Skip] }; } } }