From e802fa63afee603e8d35c4711900c213dc89dc56 Mon Sep 17 00:00:00 2001 From: Geert van Horrik Date: Tue, 4 Jul 2017 13:31:27 +0200 Subject: [PATCH] Generate 404 (Not Found) page in the root --- src/DocNet/Config.cs | 19 +++++++++- src/DocNet/Docnet.csproj | 1 + src/DocNet/Engine.cs | 2 + src/DocNet/NotFoundNavigationElement.cs | 67 +++++++++++++++++++++++++++++++++ src/DocNet/SimpleNavigationElement.cs | 10 ++--- 5 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 src/DocNet/NotFoundNavigationElement.cs diff --git a/src/DocNet/Config.cs b/src/DocNet/Config.cs index 0b639b9..159073f 100644 --- a/src/DocNet/Config.cs +++ b/src/DocNet/Config.cs @@ -110,6 +110,21 @@ namespace Docnet } } + internal void Generate404Page(NavigationContext navigationContext) + { + var simpleNavigationElement = new NotFoundNavigationElement + { + ParentContainer = Pages + }; + + var navigatedPath = new NavigatedPath(); + navigatedPath.Push(this.Pages); + + simpleNavigationElement.GenerateOutput(this, navigatedPath, navigationContext); + + navigatedPath.Pop(); + } + internal void ClearDestinationFolder() { if(string.IsNullOrWhiteSpace(this.Destination)) @@ -151,7 +166,7 @@ namespace Docnet var activePath = new NavigatedPath(); activePath.Push(this.Pages); var searchSimpleElement = new SimpleNavigationElement() {Name = "Search", Value = "Docnet_search.htm", IsIndexElement = false, ParentContainer = this.Pages}; - searchSimpleElement.ContentProducerFunc = e=>@" + searchSimpleElement.ContentProducerFunc = (e,c,n) =>@"

Search Results

@@ -162,7 +177,7 @@ namespace Docnet

Sorry, page not found.

"; - searchSimpleElement.ExtraScriptProducerFunc = e=> @" + searchSimpleElement.ExtraScriptProducerFunc = (e,c,n) => @" "; searchSimpleElement.GenerateOutput(this, activePath, navigationContext); diff --git a/src/DocNet/Docnet.csproj b/src/DocNet/Docnet.csproj index 917c8f0..b2d7f24 100644 --- a/src/DocNet/Docnet.csproj +++ b/src/DocNet/Docnet.csproj @@ -61,6 +61,7 @@ + diff --git a/src/DocNet/Engine.cs b/src/DocNet/Engine.cs index 0857ab7..bc182cd 100644 --- a/src/DocNet/Engine.cs +++ b/src/DocNet/Engine.cs @@ -106,6 +106,8 @@ namespace Docnet _loadedConfig.CopySourceFoldersToCopy(); Console.WriteLine("Generating pages in '{0}'", _loadedConfig.Destination); _loadedConfig.Pages.GenerateOutput(_loadedConfig, new NavigatedPath(), navigationContext); + Console.WriteLine("Generating 404 page"); + _loadedConfig.Generate404Page(navigationContext); Console.WriteLine("Generating search index"); _loadedConfig.GenerateSearchData(navigationContext); Console.WriteLine("Done!"); diff --git a/src/DocNet/NotFoundNavigationElement.cs b/src/DocNet/NotFoundNavigationElement.cs new file mode 100644 index 0000000..6a1c21f --- /dev/null +++ b/src/DocNet/NotFoundNavigationElement.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using MarkdownDeep; + +namespace Docnet +{ + public class NotFoundNavigationElement : SimpleNavigationElement + { + public NotFoundNavigationElement() + { + this.Name = "Page not found"; + this.IsIndexElement = false; + this.ContentProducerFunc = GenerateContent; + } + + private string GenerateContent(SimpleNavigationElement element, Config config, NavigationContext navigationContext) + { + var stringBuilder = new StringBuilder(); + + stringBuilder.AppendLine("# Page not found (404)"); + stringBuilder.AppendLine(); + + stringBuilder.AppendLine("Unfortunately the page you were looking for does not exist. In order to help you out "); + stringBuilder.AppendLine("in the best way possible, below is the table of contents:"); + stringBuilder.AppendLine(); + + foreach (var sibling in this.ParentContainer.Value) + { + if (sibling == this) + { + continue; + } + + stringBuilder.AppendFormat("* [{0}]({1}{2}){3}", sibling.Name, "/" /* pathRelativeToRoot */, + sibling.GetFinalTargetUrl(navigationContext.PathSpecification), Environment.NewLine); + } + + var markdownContent = stringBuilder.ToString(); + + var destinationFile = Utils.MakeAbsolutePath(config.Destination, this.GetTargetURL(navigationContext.PathSpecification)); + + var htmlContent = Utils.ConvertMarkdownToHtml(markdownContent, Path.GetDirectoryName(destinationFile), config.Destination, + string.Empty, new List(), config.ConvertLocalLinks); + return htmlContent; + } + + public override string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot, NavigationContext navigationContext) + { + // Skip + return string.Empty; + } + + public override void CollectSearchIndexEntries(List collectedEntries, NavigatedPath activePath, NavigationContext navigationContext) + { + // Skip + } + + public override string GetTargetURL(PathSpecification pathSpecification) + { + return "404.htm"; + } + + public override bool IsIndexElement { get; set; } + } +} \ No newline at end of file diff --git a/src/DocNet/SimpleNavigationElement.cs b/src/DocNet/SimpleNavigationElement.cs index 53e6105..294a08d 100644 --- a/src/DocNet/SimpleNavigationElement.cs +++ b/src/DocNet/SimpleNavigationElement.cs @@ -104,7 +104,7 @@ namespace Docnet { throw new FileNotFoundException(string.Format("The specified markdown file '{0}' couldn't be found. Aborting", sourceFile)); } - content = this.ContentProducerFunc(this); + content = this.ContentProducerFunc(this, activeConfig, navigationContext); } } sb.Append(activeConfig.PageTemplateContents); @@ -116,7 +116,7 @@ namespace Docnet sb.Replace("{{RelativeTargetFileName}}", Utils.MakeRelativePathForUri(activeConfig.Destination, destinationFile).TrimEnd('/')); sb.Replace("{{Breadcrumbs}}", activePath.CreateBreadCrumbsHTML(relativePathToRoot, navigationContext.PathSpecification)); sb.Replace("{{ToC}}", activePath.CreateToCHTML(relativePathToRoot, navigationContext)); - sb.Replace("{{ExtraScript}}", (this.ExtraScriptProducerFunc == null) ? string.Empty : this.ExtraScriptProducerFunc(this)); + sb.Replace("{{ExtraScript}}", (this.ExtraScriptProducerFunc == null) ? string.Empty : this.ExtraScriptProducerFunc(this, activeConfig, navigationContext)); // the last action has to be replacing the content marker, so markers in the content which we have in the template as well aren't replaced sb.Replace("{{Content}}", content); @@ -304,11 +304,11 @@ namespace Docnet /// If null, and the target file isn't found, the engine will throw an error as there's no content. If set, it's utilized over the default markdown producer. /// Use this to produce in-line HTML for specific pages which aren't specified, like the search page. /// - public Func ContentProducerFunc { get; set; } + public Func ContentProducerFunc { get; set; } /// /// Gets or sets the extra script producer function, which, if set, produces HTML to be embedded at the extra script marker /// - public Func ExtraScriptProducerFunc { get; set; } + public Func ExtraScriptProducerFunc { get; set; } /// /// Gets the loaded markdown text from the file. @@ -316,7 +316,7 @@ namespace Docnet public string MarkdownFromFile { get; - private set; + protected set; } #endregion }