Browse Source

Docs module conditional section feature

resolves https://github.com/abpframework/abp/issues/1626
pull/2297/head
Yunus Emre Kalkan 7 years ago
parent
commit
a164e1b786
  1. 10
      modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSectionConsts.cs
  2. 8
      modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSectionDictionary.cs
  3. 67
      modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSectionFinder.cs
  4. 22
      modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSectionHtmlReplacer.cs
  5. 9
      modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionFinder.cs
  6. 9
      modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionHtmlReplacer.cs
  7. 17
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml
  8. 14
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs
  9. 80
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js

10
modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSectionConsts.cs

@ -0,0 +1,10 @@
namespace Volo.Docs.HtmlConverting
{
public class DocumentSectionConsts
{
public const string SectionOpenerPrefix = "[doc-section:";
public const string SectionOpenerKeyValueSeparator = "=";
public const string SectionOpenerPostfix = "]";
public const string SectionCloser = "[/doc-section]";
}
}

8
modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSectionDictionary.cs

@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace Volo.Docs.HtmlConverting
{
public class DocumentSectionDictionary : Dictionary<string,List<string>>
{
}
}

67
modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSectionFinder.cs

@ -0,0 +1,67 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
namespace Volo.Docs.HtmlConverting
{
public class DocumentSectionFinder : IDocumentSectionFinder
{
public ILogger<DocumentSectionFinder> Logger { get; set; }
public DocumentSectionFinder()
{
Logger = NullLogger<DocumentSectionFinder>.Instance;
}
public DocumentSectionDictionary Find(string document)
{
return FindNextSections(document, new DocumentSectionDictionary());
try
{
return FindNextSections(document, new DocumentSectionDictionary());
}
catch (Exception e)
{
Logger.LogWarning(
$"Incorrect usage of \"{DocumentSectionConsts.SectionOpenerPrefix}" +
$"KEY{DocumentSectionConsts.SectionOpenerKeyValueSeparator}" +
$"VALUE{DocumentSectionConsts.SectionOpenerPostfix}..{DocumentSectionConsts.SectionCloser}\" syntax.");
return new DocumentSectionDictionary();
}
}
private DocumentSectionDictionary FindNextSections(string targetPartOfDocument, DocumentSectionDictionary sections)
{
var startOfSection = targetPartOfDocument.IndexOf(DocumentSectionConsts.SectionOpenerPrefix, StringComparison.InvariantCulture);
if (startOfSection < 0)
{
return sections;
}
var endOfSectionOpener = targetPartOfDocument.Substring(startOfSection).IndexOf(DocumentSectionConsts.SectionOpenerPostfix, StringComparison.InvariantCulture);
var keyValueWithSeparator = targetPartOfDocument.Substring(startOfSection)
[DocumentSectionConsts.SectionOpenerPrefix.Length..endOfSectionOpener];
var keyValue = keyValueWithSeparator.Split(DocumentSectionConsts.SectionOpenerKeyValueSeparator);
var key = keyValue[0];
var value = keyValue[1];
if (sections.ContainsKey(key))
{
sections[key].AddIfNotContains(value);
}
else
{
sections.Add(key, new List<string>() { value });
}
var endOfSection = targetPartOfDocument.IndexOf(DocumentSectionConsts.SectionCloser, StringComparison.InvariantCulture)
+ DocumentSectionConsts.SectionCloser.Length;
return FindNextSections(targetPartOfDocument.Substring(endOfSection), sections);
}
}
}

22
modules/docs/src/Volo.Docs.Web/HtmlConverting/DocumentSectionHtmlReplacer.cs

@ -0,0 +1,22 @@
namespace Volo.Docs.HtmlConverting
{
public class DocumentSectionHtmlReplacer : IDocumentSectionHtmlReplacer
{
public string Replace(string document, DocumentSectionDictionary sections)
{
foreach (var key in sections)
{
foreach (var value in key.Value)
{
document = document.Replace(
DocumentSectionConsts.SectionOpenerPrefix + key.Key + DocumentSectionConsts.SectionOpenerKeyValueSeparator + value + DocumentSectionConsts.SectionOpenerPostfix,
$"<div class=\"doc-section\" data-key=\"{key.Key}\" data-value=\"{value}\" style=\"display: none\">");
}
}
document = document.Replace(DocumentSectionConsts.SectionCloser, "</div>");
return document;
}
}
}

9
modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionFinder.cs

@ -0,0 +1,9 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Docs.HtmlConverting
{
public interface IDocumentSectionFinder: ITransientDependency
{
public DocumentSectionDictionary Find(string document);
}
}

9
modules/docs/src/Volo.Docs.Web/HtmlConverting/IDocumentSectionHtmlReplacer.cs

@ -0,0 +1,9 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Docs.HtmlConverting
{
public interface IDocumentSectionHtmlReplacer : ITransientDependency
{
public string Replace(string document, DocumentSectionDictionary sections);
}
}

17
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml

@ -207,10 +207,27 @@
}
</div>
}
@if (Model.DocumentSections != null && Model.DocumentSections.Count > 0)
{
foreach (var key in Model.DocumentSections)
{
@(key.Key + ":")
<select class="doc-section-combobox mr-4 mt-2" id="@("Section" + key.Key + "ComboboxId")" data-key="@key.Key">
@foreach (var value in key.Value)
{
<option value="@value">@value</option>
}
</select>
}
}
</div>
<div class="docs-text-field">
<div data-spy="scroll" data-target="#docs-sticky-index" data-offset="0">
<article class="docs-body">
@if (Model.DocumentLanguageIsDifferent)
{
<abp-alert alert-type="Warning" dismissible="true" class="mb-0">

14
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs

@ -56,22 +56,30 @@ namespace Volo.Docs.Pages.Documents.Project
public bool DocumentLanguageIsDifferent { get; set; }
public DocumentSectionDictionary DocumentSections { get; set; }
private readonly IDocumentAppService _documentAppService;
private readonly IDocumentToHtmlConverterFactory _documentToHtmlConverterFactory;
private readonly IProjectAppService _projectAppService;
private readonly IDocumentSectionHtmlReplacer _documentSectionHtmlReplacer;
private readonly IDocumentSectionFinder _documentSectionFinder;
private readonly DocsUiOptions _uiOptions;
public IndexModel(
IDocumentAppService documentAppService,
IDocumentToHtmlConverterFactory documentToHtmlConverterFactory,
IProjectAppService projectAppService,
IOptions<DocsUiOptions> options)
IOptions<DocsUiOptions> options,
IDocumentSectionHtmlReplacer documentSectionHtmlReplacer,
IDocumentSectionFinder documentSectionFinder)
{
ObjectMapperContext = typeof(DocsWebModule);
_documentAppService = documentAppService;
_documentToHtmlConverterFactory = documentToHtmlConverterFactory;
_projectAppService = projectAppService;
_documentSectionHtmlReplacer = documentSectionHtmlReplacer;
_documentSectionFinder = documentSectionFinder;
_uiOptions = options.Value;
}
@ -374,6 +382,10 @@ namespace Volo.Docs.Pages.Documents.Project
private void ConvertDocumentContentToHtml()
{
DocumentSections = _documentSectionFinder.Find(Document.Content);
Document.Content = _documentSectionHtmlReplacer.Replace(Document.Content, DocumentSections);
var converter = _documentToHtmlConverterFactory.Create(Document.Format ?? Project.Format);
var content = converter.Convert(Project, Document, GetSpecificVersionOrLatest(), LanguageCode);

80
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js

@ -2,7 +2,7 @@
$(function () {
var initNavigationFilter = function (navigationContainerId) {
var $navigation = $("#" + navigationContainerId);
@ -102,12 +102,90 @@
);
};
var initSections = function () {
var getQueryStringParameterByName = function (name) {
var url = window.location.href;
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
};
var setQueryString = function () {
var uri = window.location.href.toString();
if (uri.indexOf("?") > 0) {
uri = uri.substring(0, uri.indexOf("?"));
}
var comboboxes = $(".doc-section-combobox");
var new_uri = uri + "?";
for (var i = 0; i < comboboxes.length; i++) {
var key = $(comboboxes[i]).data('key');
var value = comboboxes[i].value;
new_uri += key + "=" + value;
if (i !== comboboxes.length - 1) {
new_uri += "&";
}
}
window.history.replaceState({}, document.title, new_uri);
};
var changeSections = function (combobox) {
var key = $(combobox).data('key');
var value = combobox.value;
$(".doc-section[data-key=" + key + "]").hide();
$(".doc-section[data-key=" + key + "][data-value=" + value + "]").show();
localStorage["abp-doc-section-" + key] = value;
setQueryString();
};
$(".doc-section-combobox").change(function () {
changeSections(this);
});
var comboboxes = $(".doc-section-combobox");
for (var i = 0; i < comboboxes.length; i++) {
var key = $(comboboxes[i]).data("key");
var cacheValue = localStorage["abp-doc-section-" + key];
if (cacheValue) {
comboboxes[i].value = cacheValue;
}
var queryValue = getQueryStringParameterByName(key);
if (queryValue) {
comboboxes[i].value = queryValue;
}
}
for (var k = 0; k < comboboxes.length; k++) {
changeSections(comboboxes[k]);
}
};
initNavigationFilter("sidebar-scroll");
initAnchorTags(".docs-page .docs-body");
initSocialShareLinks();
initSections();
});
})(jQuery);

Loading…
Cancel
Save