diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs index 927a1a4c59..0482ef5306 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Projects/ProjectConsts.cs @@ -7,6 +7,7 @@ public const int MaxDefaultDocumentNameLength = 128; public const int MaxNavigationDocumentNameLength = 128; public const int MaxParametersDocumentNameLength = 128; + public const int MaxPartialTemplatesDocumentNameLength = 128; public const int MaxLatestVersionBranchNameLength = 128; public const int MaxVersionNameLength = 128; } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentStore.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentStore.cs index bd399a4f83..c84772ff26 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentStore.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentStore.cs @@ -57,7 +57,7 @@ namespace Volo.Docs.GitHub.Documents LocalDirectory = localDirectory, FileName = fileName, Contributors = new List(), - //Contributors = !isNavigationDocument && !isParameterDocument ? await GetContributors(commitHistoryUrl, token, userAgent): new List(), + //Contributors = !isNavigationDocument && !isParameterDocument && !isPartialTemplatesDocumentName ? await GetContributors(commitHistoryUrl, token, userAgent): new List(), Version = version, Content = await DownloadWebContentAsStringAsync(rawDocumentUrl, token, userAgent) }; diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateContent.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateContent.cs new file mode 100644 index 0000000000..5db9fc8164 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateContent.cs @@ -0,0 +1,9 @@ +namespace Volo.Docs.HtmlConverting +{ + public class DocumentPartialTemplateContent + { + public string Path { get; set; } + + public string Content { get; set; } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs new file mode 100644 index 0000000000..d3ea14921c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentPartialTemplateWithValuesDto.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace Volo.Docs.HtmlConverting +{ + public class DocumentPartialTemplateWithValuesDto + { + public string Path { get; set; } + + public Dictionary Parameters { get; set; } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs index 2d9511d05b..0738b4fd5c 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionRenderer.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; @@ -8,8 +6,10 @@ namespace Volo.Docs.HtmlConverting { public interface IDocumentSectionRenderer: ITransientDependency { - Task RenderAsync(string doucment, DocumentRenderParameters parameters); + Task RenderAsync(string doucment, DocumentRenderParameters parameters = null, List partialTemplates = null); Task>> GetAvailableParametersAsync(string document); + + Task> GetPartialTemplatesInDocumentAsync(string documentContent); } } diff --git a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs index df95bf985d..4a4f3b2142 100644 --- a/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs +++ b/modules/docs/src/Volo.Docs.Web/HtmlConverting/ScribanDocumentSectionRenderer.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using Scriban; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Volo.Docs.Documents; namespace Volo.Docs.HtmlConverting { @@ -14,6 +16,7 @@ namespace Volo.Docs.HtmlConverting private const string jsonOpener = "````json"; private const string jsonCloser = "````"; private const string docs_param = "//[doc-params]"; + private const string docs_templates = "//[doc-template]"; public ILogger Logger { get; set; } @@ -22,8 +25,13 @@ namespace Volo.Docs.HtmlConverting Logger = NullLogger.Instance; } - public async Task RenderAsync(string document, DocumentRenderParameters parameters = null) + public async Task RenderAsync(string document, DocumentRenderParameters parameters = null, List partialTemplates = null) { + if (partialTemplates != null && partialTemplates.Any()) + { + document = SetPartialTemplates(document, partialTemplates); + } + var scribanTemplate = Template.Parse(document); if (parameters == null) @@ -99,7 +107,7 @@ namespace Volo.Docs.HtmlConverting if (jsonBeginningIndex < 0) { - return (-1,-1,""); + return (-1, -1, ""); } var jsonEndingIndex = document.Substring(jsonBeginningIndex).IndexOf(jsonCloser, StringComparison.Ordinal) + jsonBeginningIndex; @@ -116,5 +124,78 @@ namespace Volo.Docs.HtmlConverting return (-1, -1, ""); } + + public async Task> GetPartialTemplatesInDocumentAsync(string documentContent) + { + var templates = new List(); + + while (documentContent.Contains(jsonOpener)) + { + var afterJsonOpener = documentContent.Substring( + documentContent.IndexOf(jsonOpener, StringComparison.Ordinal) + jsonOpener.Length); + + var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, + afterJsonOpener.IndexOf(jsonCloser, StringComparison.Ordinal)); + + documentContent = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(jsonCloser, StringComparison.Ordinal) + jsonCloser.Length); + + if (!betweenJsonOpenerAndCloser.Contains(docs_templates)) + { + continue; + } + + var json = betweenJsonOpenerAndCloser.Substring(betweenJsonOpenerAndCloser.IndexOf(docs_templates, StringComparison.Ordinal) + docs_templates.Length); + + var template = JsonConvert.DeserializeObject(json); + + templates.Add(template); + } + + return templates; + } + + private string SetPartialTemplates(string document, List templates) + { + var newDocument = new StringBuilder(); + + while (document.Contains(jsonOpener)) + { + var beforeJson = document.Substring(0, + document.IndexOf(jsonOpener, StringComparison.Ordinal) + jsonOpener.Length); + + var afterJsonOpener = document.Substring( + document.IndexOf(jsonOpener, StringComparison.Ordinal) + jsonOpener.Length); + + var betweenJsonOpenerAndCloser = afterJsonOpener.Substring(0, + afterJsonOpener.IndexOf(jsonCloser, StringComparison.Ordinal)); + + if (!betweenJsonOpenerAndCloser.Contains(docs_templates)) + { + document = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(jsonCloser, StringComparison.Ordinal) + jsonCloser.Length); + newDocument.Append(beforeJson + betweenJsonOpenerAndCloser + jsonCloser); + continue; + } + + var json = betweenJsonOpenerAndCloser.Substring(betweenJsonOpenerAndCloser.IndexOf(docs_templates, StringComparison.Ordinal) + docs_templates.Length); + + var templatePath = JsonConvert.DeserializeObject(json)?.Path; + + var template = templates.FirstOrDefault(t => t.Path == templatePath); + + var beforeTemplate = document.Substring(0, + document.IndexOf(jsonOpener, StringComparison.Ordinal)); + + newDocument.Append(beforeTemplate + template?.Content + jsonCloser); + + document = afterJsonOpener.Substring( + afterJsonOpener.IndexOf(jsonCloser, StringComparison.Ordinal) + jsonCloser.Length); + } + + newDocument.Append(document); + + return newDocument.ToString(); + } } } diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index c653068baa..82b58ad117 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Volo.Abp; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; using Volo.Abp.Domain.Entities; @@ -60,7 +61,7 @@ namespace Volo.Docs.Pages.Documents.Project public DocumentParametersDto DocumentPreferences { get; set; } - public DocumentRenderParameters UserPreferences { get; set; } + public DocumentRenderParameters UserPreferences { get; set; } = new DocumentRenderParameters(); private readonly IDocumentAppService _documentAppService; private readonly IDocumentToHtmlConverterFactory _documentToHtmlConverterFactory; @@ -394,10 +395,9 @@ namespace Volo.Docs.Pages.Documents.Project await SetDocumentPreferencesAsync(); SetUserPreferences(); - UserPreferences.Add("Document_Language_Code", LanguageCode); - UserPreferences.Add("Document_Version", Version); + var partialTemplates = await GetDocumentPartialTemplatesAsync(); - Document.Content = await _documentSectionRenderer.RenderAsync(Document.Content, UserPreferences); + Document.Content = await _documentSectionRenderer.RenderAsync(Document.Content, UserPreferences, partialTemplates); var converter = _documentToHtmlConverterFactory.Create(Document.Format ?? Project.Format); var content = converter.Convert(Project, Document, GetSpecificVersionOrLatest(), LanguageCode); @@ -418,9 +418,56 @@ namespace Volo.Docs.Pages.Documents.Project Document.Content = content; } + private async Task> GetDocumentPartialTemplatesAsync() + { + var partialTemplatesInDocument = await _documentSectionRenderer.GetPartialTemplatesInDocumentAsync(Document.Content); + + if (!partialTemplatesInDocument?.Any(t => t.Parameters != null) ?? true) + { + return null; + } + + foreach (var partialTemplates in partialTemplatesInDocument) + { + foreach (var parameter in partialTemplates.Parameters) + { + if (!UserPreferences.ContainsKey(parameter.Key)) + { + UserPreferences.Add(parameter.Key, parameter.Value); + } + else + { + UserPreferences[parameter.Key] = parameter.Value; + } + } + } + + var contents = new List(); + + foreach (var partialTemplate in partialTemplatesInDocument) + { + var content = (await _documentAppService.GetAsync(new GetDocumentInput + { + LanguageCode = LanguageCode, + Name = partialTemplate.Path, + ProjectId = Project.Id, + Version = Version + })).Content; + + contents.Add(new DocumentPartialTemplateContent + { + Path = partialTemplate.Path, + Content = content + }); + } + + return contents; + } + private void SetUserPreferences() { - UserPreferences = new DocumentRenderParameters(); + UserPreferences.Add("Document_Language_Code", LanguageCode); + UserPreferences.Add("Document_Version", Version); var cookie = Request.Cookies["AbpDocsPreferences"]; @@ -473,6 +520,7 @@ namespace Volo.Docs.Pages.Documents.Project UserPreferences.Add(parameter.Name + "_Value", parameter.Values.FirstOrDefault().Value); } } + } public async Task SetDocumentPreferencesAsync() @@ -485,6 +533,7 @@ namespace Volo.Docs.Pages.Documents.Project Version = Version }); + if (projectParameters?.Parameters == null) { return;