Browse Source

Support preview

pull/22430/head
liangshiwei 1 year ago
parent
commit
d5d282c418
  1. 2
      modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs
  2. 6
      modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs
  3. 38
      modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs
  4. 41
      modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs
  5. 4
      modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs

2
modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs

@ -178,7 +178,7 @@ namespace VoloDocs.Web
Configure<DocsDocumentPdfGeneratorOptions>(options =>
{
options.BaseUrl = configuration["App:selfUrl"];
options.CoverPagePath = "Index.md";
options.IndexPagePath = "Index.md";
});
Configure<AbpBlobStoringOptions>(options =>

6
modules/docs/src/Volo.Docs.Common.HttpApi/Volo/Docs/Documents/DocsDocumentPdfGeneratorController.cs

@ -23,8 +23,10 @@ public class DocsDocumentPdfGeneratorController : DocsControllerBase, IDocumentP
[HttpGet]
[Route("pdf")]
public Task<IRemoteStreamContent> GeneratePdfAsync(DocumentPdfGeneratorInput input)
public async Task<IRemoteStreamContent> GeneratePdfAsync(DocumentPdfGeneratorInput input)
{
return DocumentPdfGeneratorAppService.GeneratePdfAsync(input);
var streamContent = await DocumentPdfGeneratorAppService.GeneratePdfAsync(input);
Response.Headers.ContentDisposition = $"inline; filename=\"{streamContent.FileName}\"";
return streamContent;
}
}

38
modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocsDocumentPdfGeneratorOptions.cs

@ -12,14 +12,34 @@ public class DocsDocumentPdfGeneratorOptions
/// The HTML layout for the PDF document.
/// </summary>
public string HtmlLayout { get; set; }
public string HtmlStyles { get; set; }
/// <summary>
/// The HTML style for the PDF document.
/// </summary>
public string HtmlStyle { get; set; }
/// <summary>
/// The base URL for the PDF document.
/// Used for resolving relative links and images.
/// </summary>
public string BaseUrl { get; set; }
public string CoverPagePath { get; set; }
public TimeSpan PdfFileCacheExpiration { get; set; } = TimeSpan.FromDays(1);
public Func<Project, string, string, string> CalculatePdfFileName { get; set; } = (project, version, languageCode) =>
{
return $"{project.ShortName}_{version}_{languageCode}.pdf";
};
/// <summary>
/// The path to the index page of the documentation.
/// </summary>
public string IndexPagePath { get; set; }
/// <summary>
/// PDF file cache expiration time.
/// Default value is 24 hours.
/// </summary>
public TimeSpan PdfFileCacheExpiration { get; set; } = TimeSpan.FromHours(24);
/// <summary>
/// The function to calculate the PDF file name.
/// Default is "{project.ShortName}_{version}_{languageCode}.pdf".
/// </summary>
public Func<Project, string, string, string> CalculatePdfFileName { get; set; }
public DocsDocumentPdfGeneratorOptions()
{
@ -36,7 +56,7 @@ public class DocsDocumentPdfGeneratorOptions
</body>
</html>";
HtmlStyles = @"
HtmlStyle = @"
body { margin: 20px; line-height: 1.6; font-family: Arial, sans-serif;}
a { text-decoration: none; }
.page {
@ -73,5 +93,7 @@ public class DocsDocumentPdfGeneratorOptions
padding: 10px 20px;
background: #f8fafc;
}";
CalculatePdfFileName = (project, version, languageCode) => $"{project.ShortName}_{version}_{languageCode}.pdf";
}
}

41
modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/DocumentPdfGenerator.cs

@ -115,7 +115,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency
string languageCode,
PdfDocumentNode parentPdfDocumentNode = null)
{
var parameterCombinationsDocuments = new List<PdfDocumentNode>();
var groupedCombinationsDocuments = new Dictionary<string, List<PdfDocumentNode>>();
foreach (var navigation in navigations)
{
if (navigation.IgnoreOnDownload)
@ -127,7 +127,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency
var pdfDocumentNode = new PdfDocumentNode
{
Title = navigation.Text,
IgnoreOnOutline = navigation.Path == Options.Value.CoverPagePath
IgnoreOnOutline = navigation.Path == Options.Value.IndexPagePath
};
if (!navigation.Path.IsNullOrWhiteSpace() && !navigation.HasChildItems)
@ -145,14 +145,20 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency
if(parameters.Count <= 1)
{
AddParameterCombinationsDocuments(parentPdfDocumentNode, parameterCombinationsDocuments);
AddParameterCombinationsDocuments(parentPdfDocumentNode, groupedCombinationsDocuments);
}
else
{
for (var i = 1; i < parameterCombinations.Count; i++)
{
var parameterCombination = parameterCombinations[i];
parameterCombinationsDocuments.Add(new PdfDocumentNode
var key = parameterCombination.Select(x => $"{x.Key}_{x.Value}").JoinAsString("-");
if (!groupedCombinationsDocuments.ContainsKey(key))
{
groupedCombinationsDocuments[key] = [];
}
groupedCombinationsDocuments[key].Add(new PdfDocumentNode
{
Document = document,
Title = GetDocumentTitle(navigation.Text, document.Content, parameterCombination),
@ -179,7 +185,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency
if (navigation == navigations.Last())
{
AddParameterCombinationsDocuments(parentPdfDocumentNode, parameterCombinationsDocuments);
AddParameterCombinationsDocuments(parentPdfDocumentNode, groupedCombinationsDocuments);
}
}
catch (Exception e)
@ -189,15 +195,18 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency
}
}
private void AddParameterCombinationsDocuments(PdfDocumentNode parentPdfDocumentNode, List<PdfDocumentNode> parameterCombinationsDocuments)
private void AddParameterCombinationsDocuments(PdfDocumentNode parentPdfDocumentNode, Dictionary<string,List<PdfDocumentNode>> groupedCombinationsDocuments)
{
if (parentPdfDocumentNode == null)
{
AllPdfDocumentNodes.AddRange(parameterCombinationsDocuments);
}
else
{
parentPdfDocumentNode.Children.AddRange(parameterCombinationsDocuments);
foreach (var combinations in groupedCombinationsDocuments)
{
if (parentPdfDocumentNode == null)
{
AllPdfDocumentNodes.AddRange(combinations.Value);
}
else
{
parentPdfDocumentNode.Children.AddRange(combinations.Value);
}
}
}
@ -218,11 +227,11 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency
throw new UserFriendlyException($"Cannot validate navigation file '{project.NavigationDocumentName}' for the project {project.Name}.");
}
if (!Options.Value.CoverPagePath.IsNullOrWhiteSpace())
if (!Options.Value.IndexPagePath.IsNullOrWhiteSpace())
{
navigation.Items.Insert(0, new NavigationNode
{
Path = Options.Value.CoverPagePath
Path = Options.Value.IndexPagePath
});
}
@ -376,7 +385,7 @@ public class DocumentPdfGenerator : IDocumentPdfGenerator, ITransientDependency
private string NormalizeMarkdownContent(string content)
{
var pattern = @"````json\s*//$begin:math:display$doc-nav$end:math:display$[\s\S]*?````";
var pattern = @"`{3,4}json\s*//\[doc-nav\][\s\S]*?`{3,4}";
return Regex.Replace(content, pattern, string.Empty, RegexOptions.IgnoreCase);
}

4
modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Pdf/IText/ITextPdfRenderer.cs

@ -31,15 +31,13 @@ public class ITextPdfRenderer : IPdfRenderer ,ITransientDependency
var htmlBuilder = new StringBuilder();
htmlBuilder.Append(Options.Value.HtmlLayout);
htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyles);
htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.StylePlaceholder, Options.Value.HtmlStyle);
htmlBuilder.Replace(DocsDocumentPdfGeneratorOptions.ContentPlaceholder, htmlContent);
var converter = new ConverterProperties();
var tagWorkerFactory = new HtmlIdTagWorkerFactory(pdfDocument);
converter.SetTagWorkerFactory(tagWorkerFactory);
await File.WriteAllTextAsync("/Users/liangshiweis/codes/test.html", htmlBuilder.ToString());
HtmlConverter.ConvertToDocument(htmlBuilder.ToString(), pdfDocument, converter);
tagWorkerFactory.AddNamedDestinations();

Loading…
Cancel
Save