Browse Source

Merge pull request #21689 from abpframework/Lazy-expandable

Lazy expandable feature for documentation
pull/21736/head
oykuermann 1 year ago
committed by GitHub
parent
commit
dc3a6d5721
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 175
      docs/en/docs-nav.json
  2. 3
      modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs
  3. 80
      modules/docs/src/Volo.Docs.Web/Areas/Documents/DocumentNavigationController.cs
  4. 16
      modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs
  5. 28
      modules/docs/src/Volo.Docs.Web/Areas/Models/DocumentNavigation/GetNavigationNodeWithLinkModel.cs
  6. 11
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml
  7. 112
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/index.js
  8. 42
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Scripts/vs.js

175
docs/en/docs-nav.json

@ -57,6 +57,8 @@
},
{
"text": "TODO Application",
"isLazyExpandable": true,
"path": "tutorials/todo",
"items": [
{
"text": "Overview",
@ -75,6 +77,8 @@
},
{
"text": "Book Store Application",
"isLazyExpandable": true,
"path": "tutorials/book-store",
"items": [
{
"text": "Overview",
@ -155,6 +159,8 @@
},
{
"text": "Modular Monolith Application",
"isLazyExpandable": true,
"path": "tutorials/modular-crm/index.md",
"items": [
{
"text": "Overview",
@ -1893,7 +1899,170 @@
},
{
"text": "Microservice Solution",
"path": "solution-templates/microservice"
"isLazyExpandable": true,
"path": "solution-templates/microservice",
"items":[
{
"text": "Overview",
"path": "solution-templates/microservice"
},
{
"text": "Solution Structure",
"path": "solution-templates/microservice/solution-structure.md"
},
{
"text": "Main Components",
"items": [
{
"text": "Overview",
"path": "solution-templates/microservice/main-components"
},
{
"text": "Microservices",
"path": "solution-templates/microservice/microservices.md"
},
{
"text": "API Gateways",
"path": "solution-templates/microservice/api-gateways.md"
},
{
"text": "Web Applications",
"path": "solution-templates/microservice/web-applications.md"
},
{
"text": "Mobile Applications",
"path": "solution-templates/microservice/mobile-applications.md"
}
]
},
{
"text": "Built-In Features",
"items": [
{
"text": "Overview",
"path": "solution-templates/microservice/built-in-features.md"
},
{
"text": "Authentication",
"path": "solution-templates/microservice/authentication.md"
},
{
"text": "Database configurations",
"path": "solution-templates/microservice/database-configurations.md"
},
{
"text": "Logging (with Serilog and Elasticsearch)",
"path": "solution-templates/microservice/logging.md"
},
{
"text": "Monitoring (with Prometheus and Grafana)",
"path": "solution-templates/microservice/monitoring.md"
},
{
"text": "Swagger integration",
"path": "solution-templates/microservice/swagger.md"
},
{
"text": "Permission management",
"path": "solution-templates/microservice/permission-management.md"
},
{
"text": "Feature management",
"path": "solution-templates/microservice/feature-management.md"
},
{
"text": "Localization system",
"path": "solution-templates/microservice/localization-system.md"
},
{
"text": "Background Jobs",
"path": "solution-templates/microservice/background-jobs.md"
},
{
"text": "Background Workers",
"path": "solution-templates/microservice/background-workers.md"
},
{
"text": "Distributed Locking",
"path": "solution-templates/microservice/distributed-locking.md"
},
{
"text": "Distributed Cache",
"path": "solution-templates/microservice/distributed-cache.md"
},
{
"text": "Multi-Tenancy",
"path": "solution-templates/microservice/multi-tenancy.md"
},
{
"text": "BLOB Storing",
"path": "solution-templates/microservice/blob-storing.md"
},
{
"text": "CORS configuration",
"path": "solution-templates/microservice/cors-configuration.md"
}
]
},
{
"text": "Communication",
"items":[
{
"text": "Overview",
"path": "solution-templates/microservice/communication.md"
},
{
"text": "HTTP API Calls",
"path": "solution-templates/microservice/http-api-calls.md"
},
{
"text": "gRPC Calls",
"path": "solution-templates/microservice/grpc-calls.md"
},
{
"text": "Distributed Events",
"path": "solution-templates/microservice/distributed-events.md"
}
]
},
{
"text": "Helm Charts and Kubernetes",
"path": "solution-templates/microservice/helm-charts-and-kubernetes.md"
},
{
"text": "Guides",
"items": [
{
"text": "Overview",
"path": "solution-templates/microservice/guides.md"
},
{
"text": "Adding new microservices",
"path": "solution-templates/microservice/adding-new-microservices.md"
},
{
"text": "Adding new applications",
"path": "solution-templates/microservice/adding-new-applications.md"
},
{
"text": "Adding new API gateways",
"path": "solution-templates/microservice/adding-new-api-gateways.md"
},
{
"text": "Mono-repo vs multiple repository approaches",
"path": "solution-templates/microservice/mono-repo-vs-multiple-repository-approaches.md"
},
{
"text": "Authoring unit and integration tests",
"path": "solution-templates/microservice/authoring-unit-and-integration-tests.md"
},
{
"text": "How to use with ABP Suite",
"path": "solution-templates/microservice/how-to-use-with-abp-suite.md"
}
]
}
]
},
{
"text": "Application Module",
@ -1981,6 +2150,8 @@
},
{
"text": "IdentityServer",
"isLazyExpandable": true,
"path": "modules/identity-server.md",
"items": [
{
"text": "Overview",
@ -2003,6 +2174,8 @@
},
{
"text": "OpenIddict",
"isLazyExpandable": true,
"path": "modules/openiddict.md",
"items": [
{
"text": "Overview",

3
modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs

@ -16,6 +16,9 @@ namespace Volo.Docs.Documents
[JsonPropertyName("items")]
public List<NavigationNode> Items { get; set; }
[JsonPropertyName("isLazyExpandable")]
public bool IsLazyExpandable { get; set; }
[JsonPropertyName("isIndex")]
public bool IsIndex { get; set; }

80
modules/docs/src/Volo.Docs.Web/Areas/Documents/DocumentNavigationController.cs

@ -0,0 +1,80 @@
using System;
using System.Threading.Tasks;
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Docs.Areas.Models.DocumentNavigation;
using Volo.Docs.Documents;
using Volo.Docs.Utils;
namespace Volo.Docs.Areas.Documents;
[RemoteService(Name = DocsRemoteServiceConsts.RemoteServiceName)]
[Area(DocsRemoteServiceConsts.ModuleName)]
[ControllerName("DocumentNavigation")]
[Route("/docs/document-navigation")]
public class DocumentNavigationController : AbpController
{
private readonly IDocumentAppService _documentAppService;
private readonly IDocsLinkGenerator _docsLinkGenerator;
public DocumentNavigationController(IDocumentAppService documentAppService, IDocsLinkGenerator docsLinkGenerator)
{
_documentAppService = documentAppService;
_docsLinkGenerator = docsLinkGenerator;
}
[HttpGet]
[Route("")]
public virtual async Task<NavigationNode> GetNavigationAsync(GetNavigationNodeWithLinkModel input)
{
var navigationNode = await _documentAppService.GetNavigationAsync(new GetNavigationDocumentInput
{
LanguageCode = input.LanguageCode,
Version = input.Version,
ProjectId = input.ProjectId
});
NormalPath(navigationNode, input);
return navigationNode;
}
protected virtual void NormalPath(NavigationNode node, GetNavigationNodeWithLinkModel input)
{
if (node.HasChildItems)
{
foreach (var item in node.Items)
{
NormalPath(item, input);
}
}
if (UrlHelper.IsExternalLink(node.Path))
{
return;
}
node.Path = RemoveFileExtensionFromPath(node.Path, input.ProjectFormat);
if (node.Path.IsNullOrWhiteSpace())
{
node.Path = "javascript:;";
return;
}
node.Path = _docsLinkGenerator.GenerateLink(input.ProjectName, input.LanguageCode, input.RouteVersion, node.Path);
}
private string RemoveFileExtensionFromPath(string path, string projectFormat)
{
if (path == null)
{
return null;
}
return path.EndsWith("." + projectFormat)
? path.Left(path.Length - projectFormat.Length - 1)
: path;
}
}

16
modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs

@ -72,11 +72,14 @@ namespace Volo.Docs.Areas.Documents.TagHelpers
var isAnyNodeOpenedInThisLevel = IsAnyNodeOpenedInThisLevel(node);
node.Items?.ForEach(innerNode =>
if (!node.IsLazyExpandable || isAnyNodeOpenedInThisLevel)
{
content += GetParentNode(innerNode, isAnyNodeOpenedInThisLevel);
});
node.Items?.ForEach(innerNode =>
{
content += GetParentNode(innerNode, isAnyNodeOpenedInThisLevel);
});
}
var result = node.IsEmpty ? content : GetLeafNode(node, content);
return result;
@ -121,6 +124,11 @@ namespace Volo.Docs.Areas.Documents.TagHelpers
listItemCss += " selected-tree";
}
if (node.IsLazyExpandable)
{
listItemCss += " lazy-expand";
}
string listInnerItem;
if (node.Path.IsNullOrEmpty() && node.IsLeaf)
{

28
modules/docs/src/Volo.Docs.Web/Areas/Models/DocumentNavigation/GetNavigationNodeWithLinkModel.cs

@ -0,0 +1,28 @@
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation;
using Volo.Docs.Language;
using Volo.Docs.Projects;
namespace Volo.Docs.Areas.Models.DocumentNavigation;
public class GetNavigationNodeWithLinkModel
{
public Guid ProjectId { get; set; }
[DynamicStringLength(typeof(ProjectConsts), nameof(ProjectConsts.MaxVersionNameLength))]
public string Version { get; set; }
[Required]
[DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxLanguageCodeLength))]
public string LanguageCode { get; set; }
[Required]
public string ProjectName { get; set; }
[Required]
public string ProjectFormat { get; set; }
[Required]
public string RouteVersion { get; set; }
}

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

@ -53,6 +53,17 @@
@if (Model.LoadSuccess)
{
<script type="text/javascript">
var doc = doc || {};
doc.project = {
id: '@Model.Project.Id',
name: '@Model.Project.ShortName',
languageCode: '@Model.LanguageCode',
version: '@Model.Version',
format: '@Model.Project.Format',
routeVersion: '@(Model.LatestVersionInfo == null || Model.LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Model.Version)'
}
</script>
<abp-script-bundle name="@typeof(IndexModel).FullName">
<abp-script type="@typeof(MalihuCustomScrollbarPluginScriptBundleContributor)"/>
<abp-script type="@typeof(ClipboardScriptBundleContributor)"/>

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

@ -1,5 +1,76 @@
var doc = doc || {};
(function ($) {
$(function () {
doc.lazyExpandableNavigation = {
isAllLoaded: false,
findNode : function(text, href, node){
if(node.text === text && node.path === href && node.isLazyExpandable){
return node;
}
if(node.items){
for (let i = 0; i < node.items.length; i++) {
var result = doc.lazyExpandableNavigation.findNode(text, href, node.items[i]);
if(result){
return result;
}
}
}
return null;
},
renderNodeAsHtml : function($lazyLiElement, node, isRootLazyNode){
if(node.isEmpty){
return;
}
var textCss = node.path === "javascript:;" ? "": "tree-toggle";
var uiCss = isRootLazyNode ? "" : "style='display: none;'";
var $ul = $(`<ul class="nav nav-list tree" ${uiCss}></ul>`);
var $li = $(`<li class="${node.hasChildItems ? 'nav-header' : 'last-link'}"></li>`);
$li.append(`<span class="plus-icon"> <i class="fa fa-${node.hasChildItems ? 'chevron-right' : node.path === "javascript:;" ? 'has-link' : 'no-link'}"></i></span><a href="${node.path}" class="${textCss}">${node.text}</a>`)
if(node.isLazyExpandable){
$li.addClass("lazy-expand");
}else if(node.hasChildItems){
node.items.forEach(function(item){
doc.lazyExpandableNavigation.renderNodeAsHtml($li, item, false);
});
}
$ul.append($li);
$lazyLiElement.append($ul)
window.Toc.helpers.initNavEvent();
},
loadAll : function(lazyLiElements){
if(doc.lazyExpandableNavigation.isAllLoaded){
return;
}
for(var i = 0; i < lazyLiElements.length; i++){
var $li = $(lazyLiElements[i]);
if($li.has("ul").length === 0){
var $a = $li.find("a");
var node = doc.lazyExpandableNavigation.findNode($a.text(), $a.attr("href"), doc.project.navigation);
node.items.forEach(item => {
doc.lazyExpandableNavigation.renderNodeAsHtml($li, item, true);
})
}
var childLazyLiElements = $li.find("li.lazy-expand");
if(childLazyLiElements.length > 0){
doc.lazyExpandableNavigation.isAllLoaded = false;
doc.lazyExpandableNavigation.loadAll(childLazyLiElements);
}
initLazyExpandNavigation();
}
doc.lazyExpandableNavigation.isAllLoaded = true;
}
}
var initNavigationFilter = function (navigationContainerId) {
var $navigation = $('#' + navigationContainerId);
@ -23,6 +94,8 @@
return;
}
doc.lazyExpandableNavigation.loadAll($navigation.find("li.lazy-expand"));
var filteredItems = $navigation
.find('li > a')
.filter(function () {
@ -98,6 +171,23 @@
});
};
var initDocProject = function(){
abp.ajax({
type :"GET",
url: '/docs/document-navigation',
data: {
projectId: doc.project.id,
version: doc.project.version,
routeVersion: doc.project.routeVersion,
languageCode: doc.project.languageCode,
projectName: doc.project.name,
projectFormat: doc.project.format
}
}).done(data => {
doc.project.navigation = data;
})
}
var initSocialShareLinks = function () {
var pageHeader = $('.docs-body').find('h1, h2').first().text();
@ -272,6 +362,26 @@
}
};
var initLazyExpandNavigation = function(){
$("li .lazy-expand").off('click');
$("li .lazy-expand").on('click', function(){
var $this = $(this);
if($this.has("ul").length > 0){
return;
}
var $a = $this.find("a");
var node = doc.lazyExpandableNavigation.findNode($a.text(), $a.attr("href") , doc.project.navigation);
node.items.forEach(item => {
doc.lazyExpandableNavigation.renderNodeAsHtml($this, item, true);
})
initLazyExpandNavigation();
});
}
initDocProject();
initNavigationFilter('sidebar-scroll');
initAnchorTags('.docs-page .docs-body');
@ -279,6 +389,8 @@
initSocialShareLinks();
initSections();
initLazyExpandNavigation();
Element.prototype.querySelector = function (selector) {
var result = $(this).find(decodeURI(selector));

42
modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Scripts/vs.js

@ -1,23 +1,7 @@
(function ($) {
$(function () {
$('li:not(.last-link) a.tree-toggle').click(function () {
$(this).parent().children('ul.tree').toggle(100);
$(this).closest('li').toggleClass('selected-tree');
});
$('li:not(.last-link) span.plus-icon i.fa-chevron-right').click(
function () {
var $element = $(this).parent();
var $filter = $('.docs-version #filter');
if ($filter && $filter.val() != ''){
return;
}
$element.parent().children('ul.tree').toggle(100);
$element.closest('li').toggleClass('selected-tree');
}
);
window.Toc.helpers.initNavEvent();
var scrollTopBtn = $('.scroll-top-btn');
var enoughHeight = $('.docs-sidebar-wrapper > .docs-top').height();
@ -159,6 +143,30 @@
$li.append($a);
return $li;
};
window.Toc.helpers.initNavEvent = function () {
$('li:not(.last-link) a.tree-toggle').off('click');
$('li:not(.last-link) span.plus-icon i.fa-chevron-right').off('click');
$('li:not(.last-link) a.tree-toggle').click(function () {
$(this).parent().children('ul.tree').toggle(100);
$(this).closest('li').toggleClass('selected-tree');
});
$('li:not(.last-link) span.plus-icon i.fa-chevron-right').click(
function () {
var $element = $(this).parent();
var $filter = $('.docs-version #filter');
if ($filter && $filter.val() != ''){
return;
}
$element.parent().children('ul.tree').toggle(100);
$element.closest('li').toggleClass('selected-tree');
}
);
}
function docsCriteria() {
var docsContentWidth = $('.docs-content').width() - 74;

Loading…
Cancel
Save