Browse Source

Refactored. And added tree tag helper.

pull/441/head
Alper Ebicoglu 8 years ago
parent
commit
85c5faf90f
  1. 50
      modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs
  2. 23
      modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs
  3. 6
      modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/IDocumentAppService.cs
  4. 5
      modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs
  5. 26
      modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs
  6. 64
      modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/GithubDocumentStore.cs
  7. 3
      modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/IDocumentStore.cs
  8. 9
      modules/docs/src/Volo.Docs.Web/DocsWebConsts.cs
  9. 49
      modules/docs/src/Volo.Docs.Web/Helpers/TagHelpers/TreeTagHelper.cs
  10. 9
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml
  11. 7
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs
  12. 36
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml
  13. 62
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs
  14. 18
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/VersionInfo.cs
  15. 3
      modules/docs/src/Volo.Docs.Web/Pages/Documents/_ViewImports.cshtml

50
modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs

@ -0,0 +1,50 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Volo.Docs.Projects;
namespace Volo.Docs.Documents
{
public class DocumentWithDetailsDto
{
public string Title { get; set; }
public string Content { get; set; }
public string Format { get; set; }
public string EditLink { get; set; }
public string RootUrl { get; set; }
public string RawRootUrl { get; set; }
public string Version { get; set; }
public ProjectDto Project { get; set; }
}
public class NavigationNode
{
[JsonProperty("text")]
public string Text { get; set; }
[JsonProperty("path")]
public string Path { get; set; }
[JsonProperty("items")]
public List<NavigationNode> Items { get; set; }
}
public class NavigationWithDetailsDto : DocumentWithDetailsDto
{
[JsonProperty("items")]
public NavigationNode RootItem { get; set; }
public void ConvertItems()
{
RootItem = string.IsNullOrWhiteSpace(Content) ?
new NavigationNode() :
JsonConvert.DeserializeObject<NavigationNode>(Content);
}
}
}

23
modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs

@ -1,23 +0,0 @@
using Volo.Docs.Projects;
namespace Volo.Docs.Documents
{
public class DocumentWithDetailsDto
{
public string Title { get; set; }
public string Content { get; set; }
public string Format { get; set; }
public string EditLink { get; set; }
public string RootUrl { get; set; }
public string RawRootUrl { get; set; }
public string Version { get; set; }
public ProjectDto Project { get; set; }
}
}

6
modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/IDocumentAppService.cs

@ -6,9 +6,11 @@ namespace Volo.Docs.Documents
{
public interface IDocumentAppService : IApplicationService
{
Task<DocumentWithDetailsDto> GetByNameAsync(string projectShortName, string documentName, string version);
Task<DocumentWithDetailsDto> GetByNameAsync(string projectShortName, string documentName, string version,
bool normalize);
Task<DocumentWithDetailsDto> GetNavigationDocumentAsync(string projectShortName, string version);
Task<NavigationWithDetailsDto> GetNavigationDocumentAsync(string projectShortName, string version,
bool normalize);
Task<List<string>> GetVersions(string projectShortName, string documentName);
}

5
modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs

@ -11,7 +11,10 @@ namespace Volo.Docs
{
CreateMap<Project, ProjectDto>();
CreateMap<Document, DocumentWithDetailsDto>()
.Ignore(x => x.Project);
.Ignore(x => x.Project);
CreateMap<DocumentWithDetailsDto, NavigationWithDetailsDto>()
.Ignore(x => x.RootItem);
}
}
}

26
modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs

@ -26,25 +26,26 @@ namespace Volo.Docs.Documents
_documentStoreFactory = documentStoreFactory;
}
public async Task<DocumentWithDetailsDto> GetByNameAsync(string projectShortName, string documentName, string version)
public async Task<DocumentWithDetailsDto> GetByNameAsync(string projectShortName, string documentName, string version, bool normalize)
{
var project = await _projectRepository.FindByShortNameAsync(projectShortName);
return await GetDocument(project, documentName, version);
return await GetDocument(project, documentName, version, normalize);
}
public async Task<DocumentWithDetailsDto> GetNavigationDocumentAsync(string projectShortName, string version)
public async Task<NavigationWithDetailsDto> GetNavigationDocumentAsync(string projectShortName, string version, bool normalize)
{
var project = await _projectRepository.FindByShortNameAsync(projectShortName);
return await GetDocument(project, project.NavigationDocumentName, version);
return ObjectMapper.Map<DocumentWithDetailsDto, NavigationWithDetailsDto>(
await GetDocument(project, project.NavigationDocumentName, version, normalize));
}
private async Task<DocumentWithDetailsDto> GetDocument(Project project, string documentName, string version)
private async Task<DocumentWithDetailsDto> GetDocument(Project project, string documentName, string version, bool normalize)
{
if (project == null)
{
throw new EntityNotFoundException($"Project Not Found!");
throw new EntityNotFoundException("Project Not Found!");
}
if (string.IsNullOrWhiteSpace(documentName))
@ -52,16 +53,19 @@ namespace Volo.Docs.Documents
documentName = project.DefaultDocumentName;
}
var documentStore = _documentStoreFactory.Create(project);
IDocumentStore documentStore = _documentStoreFactory.Create(project);
var document = await documentStore.FindDocumentByNameAsync(project, documentName, version);
var dto = ObjectMapper.Map<Document, DocumentWithDetailsDto>(document);
dto.Project = ObjectMapper.Map<Project, ProjectDto>(project);
dto.Content = NormalizeLinks(dto.Content, project.ShortName, version);
dto.Content = NormalizeImages(dto.Content, dto.RawRootUrl);
if (normalize)
{
dto.Content = NormalizeLinks(dto.Content, project.ShortName, version);
dto.Content = NormalizeImages(dto.Content, dto.RawRootUrl);
}
return dto;
}
@ -99,7 +103,7 @@ namespace Volo.Docs.Documents
private async Task SetVersionsToCache(string projectShortName, List<string> versions)
{
var options = new DistributedCacheEntryOptions(){SlidingExpiration = TimeSpan.FromDays(1)};
var options = new DistributedCacheEntryOptions() { SlidingExpiration = TimeSpan.FromDays(1) };
await _distributedCache.SetAsync(projectShortName, versions, options);
}

64
modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/GithubDocumentStore.cs

@ -3,48 +3,70 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Octokit;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Services;
using ProductHeaderValue = Octokit.ProductHeaderValue;
using Project = Volo.Docs.Projects.Project;
namespace Volo.Docs.Documents
{
public class GithubDocumentStore : IDocumentStore, ITransientDependency
public class GithubDocumentStore : DomainService, IDocumentStore
{
public const string Type = "Github"; //TODO: Conver to "github"
public const string Type = "Github"; //TODO: Convert to "github"
public async Task<Document> FindDocumentByNameAsync(Project project, string documentName, string version)
{
var rootUrl = project.ExtraProperties["GithubRootUrl"].ToString().Replace("_version_/", version + "/").Replace("www.","");
var rootUrl = project.ExtraProperties["GithubRootUrl"].ToString().Replace("_version_/", version + "/").Replace("www.", "");
var token = project.ExtraProperties["GithubAccessToken"]?.ToString();
var rawRootUrl = rootUrl.Replace("github.com", token + "raw.githubusercontent.com").Replace("/tree/", "/");
var rawUrl = rawRootUrl + $"{documentName}.md";
var editLink = rootUrl.Replace("/tree/", "/blob/") + $"{documentName}.md";
var rawUrl = rawRootUrl + documentName;
var editLink = rootUrl.Replace("/tree/", "/blob/") + documentName;
using (var webClient = new WebClient())
var content = DownloadWebContent(documentName, rawUrl);
return await Task.FromResult(new Document
{
string content;
Title = documentName,
Content = content,
EditLink = editLink,
RootUrl = rootUrl,
RawRootUrl = rawRootUrl,
Format = project.Format
});
}
private string DownloadWebContent(string documentName, string rawUrl)
{
using (var webClient = new WebClient())
{
try
{
content = webClient.DownloadString(rawUrl);
return webClient.DownloadString(rawUrl);
}
catch (Exception)
catch (WebException ex)
{
content = "The Document doesn't exist.";
}
Logger.LogError(ex, ex.Message);
if (ex.Status == WebExceptionStatus.ProtocolError)
{
if (ex.Response != null && ex.Response is HttpWebResponse response)
{
if (response.StatusCode == HttpStatusCode.NotFound)
{
return $"The document {documentName} not found in this version!";
}
}
}
return new Document
return "An error occured while getting the document " + documentName;
}
catch (Exception ex)
{
Title = documentName,
Content = content,
EditLink = editLink,
RootUrl = rootUrl,
RawRootUrl = rawRootUrl,
Format = project.Format
};
Logger.LogError(ex, ex.Message);
return "An error occured while getting the document " + documentName;
}
}
}
@ -53,7 +75,7 @@ namespace Volo.Docs.Documents
var gitHubClient = new GitHubClient(new ProductHeaderValue("AbpWebSite"));
var url = project.ExtraProperties["GithubRootUrl"].ToString();
var releases = await gitHubClient.Repository.Release.GetAll(GetGithubOrganizationNameFromUrl(url), GetGithubRepositoryNameFromUrl(url));
return releases.OrderByDescending(r => r.PublishedAt).Select(r => r.TagName).ToList();
}

3
modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/IDocumentStore.cs

@ -1,10 +1,11 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.Docs.Projects;
namespace Volo.Docs.Documents
{
public interface IDocumentStore
public interface IDocumentStore : IDomainService
{
Task<Document> FindDocumentByNameAsync(Project project, string documentName, string version);

9
modules/docs/src/Volo.Docs.Web/DocsWebConsts.cs

@ -0,0 +1,9 @@
using Volo.Docs.Pages.Documents.Project;
namespace Volo.Docs
{
public class DocsWebConsts
{
public static VersionInfo DefaultVersion = new VersionInfo("Unstable", "master"); //can be *latest* as well.
}
}

49
modules/docs/src/Volo.Docs.Web/Helpers/TagHelpers/TreeTagHelper.cs

@ -0,0 +1,49 @@
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Docs.Documents;
namespace Volo.Docs.Helpers.TagHelpers
{
[HtmlTargetElement("ul", Attributes = "navigation-items")]
public class TreeTagHelper : TagHelper
{
//private readonly IHttpContextAccessor _contextAccessor;
private const string LiItemTemplate = @"<li><label class='tree-toggle nav-header'><span class='plus-icon'><i class='fa fa-chevron-down'></i></span></label><a href='{0}'>{1}</a>{2}</li>";
private const string UlItemTemplate = @"<ul class='nav nav-list tree'>{0}</ul>";
//public TreeTagHelper(IHttpContextAccessor contextAccessor)
//{
// _contextAccessor = contextAccessor;
//}
[HtmlAttributeName("navigation-items")]
public NavigationNode RootItem { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var rootUl = string.Format(UlItemTemplate, GetNodeHtml(RootItem));
output.Content.AppendHtml(rootUl);
//output.Attributes.SetAttribute("item-count", test);
}
private static string GetNodeHtml(NavigationNode node)
{
var childContent = "";
if (node.Items != null && node.Items.Any())
{
node.Items.ForEach(innerNode =>
{
childContent += string.Format(UlItemTemplate, GetNodeHtml(innerNode));
});
}
var li = string.Format(LiItemTemplate, string.IsNullOrWhiteSpace(node.Path) ? "#" : node.Path, node.Text, childContent);
return li;
}
}
}

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

@ -1,4 +1,5 @@
@page
@using Volo.Docs
@using Volo.Docs.Pages.Documents
@model IndexModel
@{
@ -10,7 +11,13 @@
<ul>
@foreach (var project in Model.Projects)
{
<li><a asp-page="./Project/Index" asp-route-projectName="@project.ShortName" asp-route-version="latest">@project.Name</a></li>
<li>
<a asp-page="./Project/Index"
asp-route-projectName="@project.ShortName"
asp-route-version="@DocsWebConsts.DefaultVersion.Version">
@project.Name
</a>
</li>
}
</ul>
}

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

@ -24,7 +24,12 @@ namespace Volo.Docs.Pages.Documents
if (result.Items.Count == 1)
{
var project = result.Items[0];
return RedirectToPage("./Project/Index", new { projectName = project.ShortName, version = "latest", documentName = project.DefaultDocumentName });
return RedirectToPage("./Project/Index", new
{
projectName = project.ShortName,
version = DocsWebConsts.DefaultVersion.Version,
documentName = project.DefaultDocumentName
});
}
Projects = result.Items;

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

@ -1,4 +1,5 @@
@page
@using Volo.Docs.Helpers.TagHelpers;
@model Volo.Docs.Pages.Documents.Project.IndexModel
@{
ViewBag.FluidLayout = true;
@ -13,7 +14,6 @@
<script src="~/lib/anchor-js/anchor.min.js"></script>
<script src="~/lib/jquery-unveil/jquery.unveil.js" charset="UTF-8"></script>
<script src="~/lib/clipboard/dist/clipboard.min.js"></script>
<script src="~/pages/documents/project/index.js" charset="UTF-8"></script>
}
@ -57,7 +57,7 @@
{
Text = v.DisplayText,
Value = "/documents/" + Model.ProjectName + "/" + v.Version + "/" + Model.DocumentName,
Selected = (v.Version == Model.Version)
Selected = v.IsSelected
}), new { @class = "form-control flat" })
<button class="btn btn-link bd-search-docs-toggle d-md-none p-0 ml-3"
@ -76,8 +76,34 @@
}
<nav class="bd-links" id="bd-docs-nav">
@* TODO: removed collapse class, why it's needed? *@
@Html.Raw(Model.NavigationDocument.Content)
<ul navigation-items="@Model.Navigation.RootItem"></ul>
@*@if (Model.Navigation.RootItem != null)
{
<ul class="nav nav-list" id="sidebar-scroll">
@if (Model.Navigation.RootItem.Items.Any())
{
for (var i = 0; i < Model.Navigation.RootItem.Items.Count; i++)
{
var item = Model.Navigation.RootItem.Items[i];
<li>
<label class="tree-toggle nav-header">
<span class="plus-icon">
<i class="fa fa-chevron-down"></i>
</span>
</label>
<a href="@item.Path">@item.Text</a>
</li>
}
}
</ul>
}*@
</nav>
</abp-column>
@ -88,7 +114,7 @@
</div>
<h2 class="document-title">@Model.Document.Title</h2>
<div class="document-toolbar">
@if (!string.IsNullOrEmpty(Model.Document.EditLink))
{

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

@ -24,7 +24,7 @@ namespace Volo.Docs.Pages.Documents.Project
public List<VersionInfo> Versions { get; private set; }
public DocumentWithDetailsDto NavigationDocument { get; private set; }
public NavigationWithDetailsDto Navigation { get; private set; }
private readonly IDocumentAppService _documentAppService;
private readonly IDocumentFormattingFactory _documentFormattingFactory;
@ -41,36 +41,66 @@ namespace Volo.Docs.Pages.Documents.Project
.Select(v => new VersionInfo(v, v))
.ToList();
var latestVersion = Versions.First();
latestVersion.DisplayText = $"{latestVersion.Version} - latest";
latestVersion.Version = latestVersion.Version;
AddDefaultVersionIfNotContains();
if (string.Equals(Version, "latest", StringComparison.OrdinalIgnoreCase) || !Versions.Exists(v => v.Version == Version))
var versionFromUrl = Versions.FirstOrDefault(v => v.Version == Version);
if (versionFromUrl != null)
{
versionFromUrl.IsSelected = true;
}
else if (string.Equals(Version, "latest", StringComparison.InvariantCultureIgnoreCase))
{
latestVersion.IsSelected = true;
}
else
{
Version = latestVersion.Version;
Versions.First().IsSelected = true;
}
latestVersion.DisplayText = $"{latestVersion.Version} (latest)";
latestVersion.Version = "latest";
//if (string.Equals(Version, "latest", StringComparison.OrdinalIgnoreCase) || !Versions.Exists(v => v.Version == Version))
//{
// Version = latestVersion.Version;
// latestVersion.IsSelected = true;
//}
Document = await _documentAppService.GetByNameAsync(ProjectName, DocumentName, Version);
if (Version == null)
{
Version = Versions.Single(x => x.IsSelected).Version;
}
Document = await _documentAppService.GetByNameAsync(ProjectName, DocumentName, Version, true);
var documentFormatting = _documentFormattingFactory.Create(Document.Format ?? "md");
Document.Content = documentFormatting.Format(Document.Content);
NavigationDocument = await _documentAppService.GetNavigationDocumentAsync(ProjectName, Version);
var navigationDocumentFormatting = _documentFormattingFactory.Create(NavigationDocument.Format);
NavigationDocument.Content = navigationDocumentFormatting.Format(NavigationDocument.Content);
Navigation = await _documentAppService.GetNavigationDocumentAsync(ProjectName, Version, false);
Navigation.ConvertItems();
}
public class VersionInfo
private void AddDefaultVersionIfNotContains()
{
public string DisplayText { get; set; }
public string Version { get; set; }
if (DocsWebConsts.DefaultVersion == null)
{
return;
}
public VersionInfo(string displayText, string version)
if (Versions.Contains(DocsWebConsts.DefaultVersion))
{
DisplayText = displayText;
Version = version;
return;
}
Versions.Insert(0, DocsWebConsts.DefaultVersion);
}
public void RenderTree()
{
}
}
}

18
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/VersionInfo.cs

@ -0,0 +1,18 @@
namespace Volo.Docs.Pages.Documents.Project
{
public class VersionInfo
{
public string DisplayText { get; set; }
public string Version { get; set; }
public bool IsSelected { get; set; }
public VersionInfo(string displayText, string version, bool isSelected = false)
{
DisplayText = displayText;
Version = version;
IsSelected = isSelected;
}
}
}

3
modules/docs/src/Volo.Docs.Web/Pages/Documents/_ViewImports.cshtml

@ -1,4 +1,5 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@addTagHelper *, Volo.Docs.Web
@addTagHelper *, Volo.Docs.Web
@addTagHelper *, Volo.Docs.Helpers

Loading…
Cancel
Save