Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
<ToolingPackagesVersion>1.1.1.4415</ToolingPackagesVersion>
<ToolingPackagesVersion>1.1.1.4520</ToolingPackagesVersion>
<AccessToNugetFeed>true</AccessToNugetFeed>
<RestoreSources>
https://api.nuget.org/v3/index.json;
Expand Down
14 changes: 8 additions & 6 deletions EssentialCSharp.Web.Tests/SiteMappingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace EssentialCSharp.Web.Tests;
public class SiteMappingTests
{
static SiteMapping HelloWorldSiteMapping => new(
key: "hello-world",
keys: ["hello-world"],
pagePath:
[
"Chapters",
Expand All @@ -15,14 +15,15 @@ public class SiteMappingTests
],
chapterNumber: 1,
pageNumber: 1,
orderOnPage: 1,
chapterTitle: "Introducing C#",
rawHeading: "Introduction",
anchorId: "hello-world",
indentLevel: 0
);

static SiteMapping CSyntaxFundamentalsSiteMapping => new(
key: "c-syntax-fundamentals",
keys: ["c-syntax-fundamentals"],
pagePath:
[
"Chapters",
Expand All @@ -32,6 +33,7 @@ public class SiteMappingTests
],
chapterNumber: 1,
pageNumber: 2,
orderOnPage: 1,
chapterTitle: "Introducing C#",
rawHeading: "C# Syntax Fundamentals",
anchorId: "c-syntax-fundamentals",
Expand All @@ -52,30 +54,30 @@ public void FindHelloWorldWithAnchorSlugReturnsCorrectSiteMap()
{
SiteMapping? foundSiteMap = GetSiteMap().Find("hello-world#hello-world");
Assert.NotNull(foundSiteMap);
Assert.Equal(HelloWorldSiteMapping, foundSiteMap);
Assert.Equivalent(HelloWorldSiteMapping, foundSiteMap);
}

[Fact]
public void FindCSyntaxFundamentalsWithSpacesReturnsCorrectSiteMap()
{
SiteMapping? foundSiteMap = GetSiteMap().Find("C# Syntax Fundamentals");
Assert.NotNull(foundSiteMap);
Assert.Equal(CSyntaxFundamentalsSiteMapping, foundSiteMap);
Assert.Equivalent(CSyntaxFundamentalsSiteMapping, foundSiteMap);
}

[Fact]
public void FindCSyntaxFundamentalsWithSpacesAndAnchorReturnsCorrectSiteMap()
{
SiteMapping? foundSiteMap = GetSiteMap().Find("C# Syntax Fundamentals#hello-world");
Assert.NotNull(foundSiteMap);
Assert.Equal(CSyntaxFundamentalsSiteMapping, foundSiteMap);
Assert.Equivalent(CSyntaxFundamentalsSiteMapping, foundSiteMap);
}

[Fact]
public void FindCSyntaxFundamentalsSanitizedWithAnchorReturnsCorrectSiteMap()
{
SiteMapping? foundSiteMap = GetSiteMap().Find("c-syntax-fundamentals#hello-world");
Assert.NotNull(foundSiteMap);
Assert.Equal(CSyntaxFundamentalsSiteMapping, foundSiteMap);
Assert.Equivalent(CSyntaxFundamentalsSiteMapping, foundSiteMap);
}
}
2 changes: 1 addition & 1 deletion EssentialCSharp.Web/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ private string FlipPage(int currentChapter, int currentPage, bool next)
return "";
}
}
return $"{siteMap.Key}#{siteMap.AnchorId}";
return $"{siteMap.Keys.First()}#{siteMap.AnchorId}";
}

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static class SiteMappingListExtensions
}
foreach (string? potentialMatch in key.GetPotentialMatches())
{
if (siteMappings.FirstOrDefault(x => x.Key == potentialMatch) is { } siteMap)
if (siteMappings.FirstOrDefault(x => x.Keys.Any(x => x == potentialMatch)) is { } siteMap)
{
return siteMap;
}
Expand Down
1 change: 1 addition & 0 deletions EssentialCSharp.Web/Services/ISiteMappingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
public interface ISiteMappingService
{
IList<SiteMapping> SiteMappings { get; }
IEnumerable<SiteMappingDto> GetTocData();
}
12 changes: 12 additions & 0 deletions EssentialCSharp.Web/Services/SiteMappingDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace EssentialCSharp.Web.Services;

// Data transfer object to pass necessary SiteMapping data info
// to frontend for use in table of contents
public class SiteMappingDto
{
public required int Level { get; set; }
public required string Key { get; set; }
public required string Href { get; set; }
public required string Title { get; set; }
public required IEnumerable<SiteMappingDto> Items { get; set; }
}
38 changes: 38 additions & 0 deletions EssentialCSharp.Web/Services/SiteMappingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,42 @@ public SiteMappingService(IWebHostEnvironment webHostEnvironment)
List<SiteMapping>? siteMappings = System.Text.Json.JsonSerializer.Deserialize<List<SiteMapping>>(File.OpenRead(path)) ?? throw new InvalidOperationException("No table of contents found");
SiteMappings = siteMappings;
}

public IEnumerable<SiteMappingDto> GetTocData()
{
return SiteMappings.GroupBy(x => x.ChapterNumber).OrderBy(x => x.Key).Select(x =>
{
IEnumerable<SiteMapping> orderedGrouping = x.OrderBy(i => i.PageNumber).ThenBy(i => i.OrderOnPage);
SiteMapping firstElement = orderedGrouping.First();
return new SiteMappingDto()
{
Level = 0,
Key = firstElement.Keys.First(),
Href = $"{firstElement.Keys.First()}#{firstElement.AnchorId}",
Title = $"Chapter {x.Key}: {firstElement.ChapterTitle}",
Items = GetItems(orderedGrouping.Skip(1), 1)
};
}
);
}

private static IEnumerable<SiteMappingDto> GetItems(IEnumerable<SiteMapping> chapterItems, int indentLevel)
{
return chapterItems
// Examine all items up until we move up to a level higher than where we're starting,
// which would indicate that we've reached the end of the entries nested under `indentationLevel`
.TakeWhile(i => i.IndentLevel >= indentLevel)
// Of all the multi-level descendants we found, take only those at the current level that we're wanting to render.
.Where(i => i.IndentLevel == indentLevel)
.Select(i => new SiteMappingDto()
{
Level = indentLevel,
Key = i.Keys.First(),
Href = $"{i.Keys.First()}#{i.AnchorId}",
Title = i.RawHeading,
// Any children of this node will be /after/ this node,
// so skip any items that are /before/ the current node.
Items = GetItems(chapterItems.SkipWhile(q => i.Keys.First() != q.Keys.First()).Skip(1), indentLevel + 1)
});
}
}
27 changes: 1 addition & 26 deletions EssentialCSharp.Web/Views/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -266,32 +266,7 @@
@await RenderSectionAsync("Scripts", required: false);
<script>
@{
object GetItems(IEnumerable<SiteMapping> chapterItems, int indentLevel) => chapterItems
// Skip the chapter entry itself
.Skip(1)
// Examine all items up until we move up to a level higher than where we're starting,
// which would indicate that we've reached the end of the entries nested under `indentationLevel`
.TakeWhile(i => i.IndentLevel >= indentLevel)
// Of all the multi-level descendants we found, take only those at the current level that we're wanting to render.
.Where(i => i.IndentLevel == indentLevel)
.Select(i => new
{
Level = indentLevel,
Key = i.Key,
Href = $"{i.Key}#{i.AnchorId}",
Title = i.RawHeading,
// Any children of this node will be /after/ this node,
// so skip any items that are /before/ the current node.
Items = GetItems(chapterItems.SkipWhile(q => i.Key != q.Key), indentLevel + 1)
});
var tocData = _SiteMappings.SiteMappings.GroupBy(x => x.ChapterNumber).OrderBy(x => x.Key).Select(x => new
{
Level = 0,
Key = x.First().Key,
Href = $"{x.First().Key}#{x.First().AnchorId}",
Title = $"Chapter {x.Key}: {x.First().ChapterTitle}",
Items = GetItems(x, 1)
});
var tocData = _SiteMappings.GetTocData();
}

PREVIOUS_PAGE = @Json.Serialize(ViewBag.PreviousPage)
Expand Down
Loading