| @@ -225,6 +225,14 @@ namespace Docnet | |||||
| } | } | ||||
| } | } | ||||
| public bool StripIndexHtm | |||||
| { | |||||
| get | |||||
| { | |||||
| return _configData.StripIndexHtm ?? false; | |||||
| } | |||||
| } | |||||
| public string ThemeName | public string ThemeName | ||||
| { | { | ||||
| get | get | ||||
| @@ -48,7 +48,8 @@ namespace Docnet | |||||
| var navigationContext = new NavigationContext | var navigationContext = new NavigationContext | ||||
| { | { | ||||
| MaxLevel = _loadedConfig.MaxLevelInToC, | MaxLevel = _loadedConfig.MaxLevelInToC, | ||||
| PathSpecification = _loadedConfig.PathSpecification | |||||
| PathSpecification = _loadedConfig.PathSpecification, | |||||
| StripIndexHtm = _loadedConfig.StripIndexHtm | |||||
| }; | }; | ||||
| GeneratePages(navigationContext); | GeneratePages(navigationContext); | ||||
| @@ -78,7 +79,9 @@ namespace Docnet | |||||
| return null; | return null; | ||||
| } | } | ||||
| var indexElement = config.Pages.GetIndexElement(config.PathSpecification); | |||||
| var navigationContext = new NavigationContext(config.PathSpecification, config.MaxLevelInToC, config.StripIndexHtm); | |||||
| var indexElement = config.Pages.GetIndexElement(navigationContext); | |||||
| if(indexElement == null) | if(indexElement == null) | ||||
| { | { | ||||
| Console.WriteLine("[ERROR] Root __index not found. The root navigationlevel is required to have an __index element"); | Console.WriteLine("[ERROR] Root __index not found. The root navigationlevel is required to have an __index element"); | ||||
| @@ -55,11 +55,11 @@ namespace Docnet | |||||
| void CollectSearchIndexEntries(List<SearchIndexEntry> collectedEntries, NavigatedPath activePath, NavigationContext navigationContext); | void CollectSearchIndexEntries(List<SearchIndexEntry> collectedEntries, NavigatedPath activePath, NavigationContext navigationContext); | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets the target URL with respect to the <see cref="PathSpecification"/>. | |||||
| /// Gets the target URL with respect to the <see cref="PathSpecification" />. | |||||
| /// </summary> | /// </summary> | ||||
| /// <param name="pathSpecification">The path specification.</param> | |||||
| /// <param name="navigationContext">The navigation context.</param> | |||||
| /// <returns></returns> | /// <returns></returns> | ||||
| string GetTargetURL(PathSpecification pathSpecification); | |||||
| string GetTargetURL(NavigationContext navigationContext); | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets a value indicating whether this element is the __index element | /// Gets a value indicating whether this element is the __index element | ||||
| @@ -11,25 +11,23 @@ namespace Docnet | |||||
| /// Gets the final URL by encoding the path and by removing the filename if it equals <c>index.htm</c>. | /// Gets the final URL by encoding the path and by removing the filename if it equals <c>index.htm</c>. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="navigationElement">The navigation element.</param> | /// <param name="navigationElement">The navigation element.</param> | ||||
| /// <param name="pathSpecification">The path specification.</param> | |||||
| /// <param name="navigationContext">The navigation context.</param> | |||||
| /// <returns></returns> | /// <returns></returns> | ||||
| public static string GetFinalTargetUrl(this INavigationElement navigationElement, PathSpecification pathSpecification) | |||||
| public static string GetFinalTargetUrl(this INavigationElement navigationElement, NavigationContext navigationContext) | |||||
| { | { | ||||
| var targetUrl = navigationElement.GetTargetURL(pathSpecification); | |||||
| var targetUrl = navigationElement.GetTargetURL(navigationContext); | |||||
| var link = HttpUtility.UrlPathEncode(targetUrl); | var link = HttpUtility.UrlPathEncode(targetUrl); | ||||
| // Disabled for now as discussed in #65 (https://github.com/FransBouma/DocNet/pull/65), but | |||||
| // is required for #44 | |||||
| //if (pathSpecification == PathSpecification.RelativeAsFolder) | |||||
| //{ | |||||
| // if (link.Length > IndexHtmFileName.Length && | |||||
| // link.EndsWith(IndexHtmFileName, StringComparison.InvariantCultureIgnoreCase)) | |||||
| // { | |||||
| // link = link.Substring(0, link.Length - IndexHtmFileName.Length); | |||||
| // } | |||||
| //} | |||||
| if (navigationContext.StripIndexHtm) | |||||
| { | |||||
| if (link.Length > IndexHtmFileName.Length && | |||||
| link.EndsWith(IndexHtmFileName, StringComparison.InvariantCultureIgnoreCase)) | |||||
| { | |||||
| link = link.Substring(0, link.Length - IndexHtmFileName.Length); | |||||
| } | |||||
| } | |||||
| return link; | |||||
| return link; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -38,15 +38,15 @@ namespace Docnet | |||||
| /// Creates the bread crumbs HTML of the elements in this path, delimited by '/' characters. | /// Creates the bread crumbs HTML of the elements in this path, delimited by '/' characters. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="relativePathToRoot">The relative path back to the URL root, e.g. ../.., so it can be used for links to elements in this path.</param> | /// <param name="relativePathToRoot">The relative path back to the URL root, e.g. ../.., so it can be used for links to elements in this path.</param> | ||||
| /// <param name="pathSpecification">The path specification.</param> | |||||
| /// <param name="navigationContext">The navigation context.</param> | |||||
| /// <returns></returns> | /// <returns></returns> | ||||
| public string CreateBreadCrumbsHTML(string relativePathToRoot, PathSpecification pathSpecification) | |||||
| public string CreateBreadCrumbsHTML(string relativePathToRoot, NavigationContext navigationContext) | |||||
| { | { | ||||
| var fragments = new List<string>(); | var fragments = new List<string>(); | ||||
| // we enumerate a stack, which enumerates from top to bottom, so we have to reverse things first. | // we enumerate a stack, which enumerates from top to bottom, so we have to reverse things first. | ||||
| foreach(var element in this.Reverse()) | foreach(var element in this.Reverse()) | ||||
| { | { | ||||
| var targetURL = element.GetTargetURL(pathSpecification); | |||||
| var targetURL = element.GetTargetURL(navigationContext); | |||||
| if(string.IsNullOrWhiteSpace(targetURL)) | if(string.IsNullOrWhiteSpace(targetURL)) | ||||
| { | { | ||||
| fragments.Add(string.Format("<li>{0}</li>", element.Name)); | fragments.Add(string.Format("<li>{0}</li>", element.Name)); | ||||
| @@ -7,15 +7,18 @@ | |||||
| MaxLevel = 2; | MaxLevel = 2; | ||||
| } | } | ||||
| public NavigationContext(PathSpecification pathSpecification, int maxLevel) | |||||
| public NavigationContext(PathSpecification pathSpecification, int maxLevel, bool stripIndexHtm) | |||||
| : this() | : this() | ||||
| { | { | ||||
| PathSpecification = pathSpecification; | PathSpecification = pathSpecification; | ||||
| MaxLevel = maxLevel; | MaxLevel = maxLevel; | ||||
| StripIndexHtm = stripIndexHtm; | |||||
| } | } | ||||
| public PathSpecification PathSpecification { get; set; } | |||||
| public int MaxLevel { get; set; } | public int MaxLevel { get; set; } | ||||
| public PathSpecification PathSpecification { get; set; } | |||||
| public bool StripIndexHtm { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -55,11 +55,11 @@ namespace Docnet | |||||
| public abstract void CollectSearchIndexEntries(List<SearchIndexEntry> collectedEntries, NavigatedPath activePath, NavigationContext navigationContext); | public abstract void CollectSearchIndexEntries(List<SearchIndexEntry> collectedEntries, NavigatedPath activePath, NavigationContext navigationContext); | ||||
| /// <summary> | /// <summary> | ||||
| /// Gets the target URL with respect to the <see cref="PathSpecification"/>. | |||||
| /// Gets the target URL with respect to the <see cref="PathSpecification" />. | |||||
| /// </summary> | /// </summary> | ||||
| /// <param name="pathSpecification">The path specification.</param> | |||||
| /// <param name="navigationContext">The navigation context.</param> | |||||
| /// <returns></returns> | /// <returns></returns> | ||||
| public abstract string GetTargetURL(PathSpecification pathSpecification); | |||||
| public abstract string GetTargetURL(NavigationContext navigationContext); | |||||
| #region Properties | #region Properties | ||||
| /// <summary> | /// <summary> | ||||
| @@ -167,7 +167,7 @@ namespace Docnet | |||||
| // first render the level header, which is the index element, if present or a label. The root always has an __index element otherwise we'd have stopped at load. | // first render the level header, which is the index element, if present or a label. The root always has an __index element otherwise we'd have stopped at load. | ||||
| var elementStartTag = "<li><span class=\"navigationgroup\"><i class=\"fa fa-caret-down\"></i> "; | var elementStartTag = "<li><span class=\"navigationgroup\"><i class=\"fa fa-caret-down\"></i> "; | ||||
| var indexElement = this.GetIndexElement(navigationContext.PathSpecification); | |||||
| var indexElement = this.GetIndexElement(navigationContext); | |||||
| if (indexElement == null) | if (indexElement == null) | ||||
| { | { | ||||
| fragments.Add(string.Format("{0}{1}</span></li>", elementStartTag, this.Name)); | fragments.Add(string.Format("{0}{1}</span></li>", elementStartTag, this.Name)); | ||||
| @@ -181,7 +181,7 @@ namespace Docnet | |||||
| else | else | ||||
| { | { | ||||
| fragments.Add(string.Format("{0}<a href=\"{1}{2}\">{3}</a></span></li>", | fragments.Add(string.Format("{0}<a href=\"{1}{2}\">{3}</a></span></li>", | ||||
| elementStartTag, relativePathToRoot, indexElement.GetFinalTargetUrl(navigationContext.PathSpecification), this.Name)); | |||||
| elementStartTag, relativePathToRoot, indexElement.GetFinalTargetUrl(navigationContext), this.Name)); | |||||
| } | } | ||||
| } | } | ||||
| // then the elements in the container. Index elements are skipped here. | // then the elements in the container. Index elements are skipped here. | ||||
| @@ -195,7 +195,7 @@ namespace Docnet | |||||
| { | { | ||||
| // just a link | // just a link | ||||
| fragments.Add(string.Format("<span class=\"navigationgroup\"><i class=\"fa fa-caret-right\"></i> <a href=\"{0}{1}\">{2}</a></span>", | fragments.Add(string.Format("<span class=\"navigationgroup\"><i class=\"fa fa-caret-right\"></i> <a href=\"{0}{1}\">{2}</a></span>", | ||||
| relativePathToRoot, this.GetFinalTargetUrl(navigationContext.PathSpecification), this.Name)); | |||||
| relativePathToRoot, this.GetFinalTargetUrl(navigationContext), this.Name)); | |||||
| } | } | ||||
| if (!this.IsRoot) | if (!this.IsRoot) | ||||
| { | { | ||||
| @@ -277,18 +277,18 @@ namespace Docnet | |||||
| return title; | return title; | ||||
| } | } | ||||
| public override string GetTargetURL(PathSpecification pathSpecification) | |||||
| public override string GetTargetURL(NavigationContext navigationContext) | |||||
| { | { | ||||
| var defaultElement = this.GetIndexElement(pathSpecification); | |||||
| var defaultElement = this.GetIndexElement(navigationContext); | |||||
| if (defaultElement == null) | if (defaultElement == null) | ||||
| { | { | ||||
| return string.Empty; | return string.Empty; | ||||
| } | } | ||||
| return defaultElement.GetTargetURL(pathSpecification) ?? string.Empty; | |||||
| return defaultElement.GetTargetURL(navigationContext) ?? string.Empty; | |||||
| } | } | ||||
| public SimpleNavigationElement GetIndexElement(PathSpecification pathSpecification) | |||||
| public SimpleNavigationElement GetIndexElement(NavigationContext navigationContext) | |||||
| { | { | ||||
| var toReturn = this.Value.FirstOrDefault(e => e.IsIndexElement) as SimpleNavigationElement; | var toReturn = this.Value.FirstOrDefault(e => e.IsIndexElement) as SimpleNavigationElement; | ||||
| if (toReturn == null) | if (toReturn == null) | ||||
| @@ -297,11 +297,11 @@ namespace Docnet | |||||
| var path = string.Empty; | var path = string.Empty; | ||||
| // Don't check parents when using relative paths since we need to walk the tree manually | // Don't check parents when using relative paths since we need to walk the tree manually | ||||
| if (pathSpecification == PathSpecification.Full) | |||||
| if (navigationContext.PathSpecification == PathSpecification.Full) | |||||
| { | { | ||||
| if (this.ParentContainer != null) | if (this.ParentContainer != null) | ||||
| { | { | ||||
| path = Path.GetDirectoryName(this.ParentContainer.GetTargetURL(pathSpecification)); | |||||
| path = Path.GetDirectoryName(this.ParentContainer.GetTargetURL(navigationContext)); | |||||
| } | } | ||||
| } | } | ||||
| @@ -313,7 +313,7 @@ namespace Docnet | |||||
| var value = string.Format("{0}{1}.md", path, nameToUse); | var value = string.Format("{0}{1}.md", path, nameToUse); | ||||
| switch (pathSpecification) | |||||
| switch (navigationContext.PathSpecification) | |||||
| { | { | ||||
| case PathSpecification.Full: | case PathSpecification.Full: | ||||
| // Default is correct | // Default is correct | ||||
| @@ -342,7 +342,7 @@ namespace Docnet | |||||
| var firstChildNavigationLevel = (NavigationLevel)this.Value.FirstOrDefault(x => x is NavigationLevel && ((NavigationLevel)x).Value.Any() && !ReferenceEquals(this, x)); | var firstChildNavigationLevel = (NavigationLevel)this.Value.FirstOrDefault(x => x is NavigationLevel && ((NavigationLevel)x).Value.Any() && !ReferenceEquals(this, x)); | ||||
| if (firstChildNavigationLevel != null) | if (firstChildNavigationLevel != null) | ||||
| { | { | ||||
| var targetUrl = firstChildNavigationLevel.Value.First().GetTargetURL(pathSpecification); | |||||
| var targetUrl = firstChildNavigationLevel.Value.First().GetTargetURL(navigationContext); | |||||
| // 3 times since we need 2 parents up | // 3 times since we need 2 parents up | ||||
| preferredPath = Path.GetDirectoryName(targetUrl); | preferredPath = Path.GetDirectoryName(targetUrl); | ||||
| @@ -359,7 +359,7 @@ namespace Docnet | |||||
| break; | break; | ||||
| default: | default: | ||||
| throw new ArgumentOutOfRangeException(nameof(pathSpecification), pathSpecification, null); | |||||
| throw new ArgumentOutOfRangeException(nameof(navigationContext.PathSpecification), navigationContext.PathSpecification, null); | |||||
| } | } | ||||
| toReturn = new SimpleNavigationElement | toReturn = new SimpleNavigationElement | ||||
| @@ -62,7 +62,7 @@ namespace Docnet | |||||
| } | } | ||||
| _relativeLinksOnPage.Clear(); | _relativeLinksOnPage.Clear(); | ||||
| var sourceFile = Utils.MakeAbsolutePath(activeConfig.Source, this.Value); | var sourceFile = Utils.MakeAbsolutePath(activeConfig.Source, this.Value); | ||||
| var destinationFile = Utils.MakeAbsolutePath(activeConfig.Destination, this.GetTargetURL(navigationContext.PathSpecification)); | |||||
| var destinationFile = Utils.MakeAbsolutePath(activeConfig.Destination, this.GetTargetURL(navigationContext)); | |||||
| var sb = new StringBuilder(activeConfig.PageTemplateContents.Length + 2048); | var sb = new StringBuilder(activeConfig.PageTemplateContents.Length + 2048); | ||||
| var content = string.Empty; | var content = string.Empty; | ||||
| this.MarkdownFromFile = string.Empty; | this.MarkdownFromFile = string.Empty; | ||||
| @@ -92,7 +92,7 @@ namespace Docnet | |||||
| continue; | continue; | ||||
| } | } | ||||
| defaultMarkdown.AppendFormat("* [{0}]({1}{2}){3}", sibling.Name, relativePathToRoot, | defaultMarkdown.AppendFormat("* [{0}]({1}{2}){3}", sibling.Name, relativePathToRoot, | ||||
| sibling.GetFinalTargetUrl(navigationContext.PathSpecification), Environment.NewLine); | |||||
| sibling.GetFinalTargetUrl(navigationContext), Environment.NewLine); | |||||
| } | } | ||||
| defaultMarkdown.Append(Environment.NewLine); | defaultMarkdown.Append(Environment.NewLine); | ||||
| content = Utils.ConvertMarkdownToHtml(defaultMarkdown.ToString(), Path.GetDirectoryName(destinationFile), activeConfig.Destination, string.Empty, _relativeLinksOnPage, activeConfig.ConvertLocalLinks); | content = Utils.ConvertMarkdownToHtml(defaultMarkdown.ToString(), Path.GetDirectoryName(destinationFile), activeConfig.Destination, string.Empty, _relativeLinksOnPage, activeConfig.ConvertLocalLinks); | ||||
| @@ -114,7 +114,7 @@ namespace Docnet | |||||
| sb.Replace("{{Path}}", relativePathToRoot); | sb.Replace("{{Path}}", relativePathToRoot); | ||||
| sb.Replace("{{RelativeSourceFileName}}", Utils.MakeRelativePathForUri(activeConfig.Destination, sourceFile).TrimEnd('/')); | sb.Replace("{{RelativeSourceFileName}}", Utils.MakeRelativePathForUri(activeConfig.Destination, sourceFile).TrimEnd('/')); | ||||
| sb.Replace("{{RelativeTargetFileName}}", Utils.MakeRelativePathForUri(activeConfig.Destination, destinationFile).TrimEnd('/')); | sb.Replace("{{RelativeTargetFileName}}", Utils.MakeRelativePathForUri(activeConfig.Destination, destinationFile).TrimEnd('/')); | ||||
| sb.Replace("{{Breadcrumbs}}", activePath.CreateBreadCrumbsHTML(relativePathToRoot, navigationContext.PathSpecification)); | |||||
| sb.Replace("{{Breadcrumbs}}", activePath.CreateBreadCrumbsHTML(relativePathToRoot, navigationContext)); | |||||
| sb.Replace("{{ToC}}", activePath.CreateToCHTML(relativePathToRoot, navigationContext)); | 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)); | ||||
| @@ -142,7 +142,7 @@ namespace Docnet | |||||
| if (!this.IsIndexElement) | if (!this.IsIndexElement) | ||||
| { | { | ||||
| var toAdd = new SearchIndexEntry(); | var toAdd = new SearchIndexEntry(); | ||||
| toAdd.Fill(this.MarkdownFromFile, this.GetTargetURL(navigationContext.PathSpecification), this.Name, activePath); | |||||
| toAdd.Fill(this.MarkdownFromFile, this.GetTargetURL(navigationContext), this.Name, activePath); | |||||
| collectedEntries.Add(toAdd); | collectedEntries.Add(toAdd); | ||||
| } | } | ||||
| activePath.Pop(); | activePath.Pop(); | ||||
| @@ -192,7 +192,7 @@ namespace Docnet | |||||
| string.IsNullOrWhiteSpace(liClass) ? string.Empty : string.Format(" class=\"{0}\"", liClass), | string.IsNullOrWhiteSpace(liClass) ? string.Empty : string.Format(" class=\"{0}\"", liClass), | ||||
| string.IsNullOrWhiteSpace(aClass) ? string.Empty : string.Format(" class=\"{0}\"", aClass), | string.IsNullOrWhiteSpace(aClass) ? string.Empty : string.Format(" class=\"{0}\"", aClass), | ||||
| relativePathToRoot, | relativePathToRoot, | ||||
| this.GetFinalTargetUrl(navigationContext.PathSpecification), | |||||
| this.GetFinalTargetUrl(navigationContext), | |||||
| this.Name)); | this.Name)); | ||||
| if (isCurrent && _relativeLinksOnPage.SelectMany(x => x.Children).Any(x => x.Level > 1)) | if (isCurrent && _relativeLinksOnPage.SelectMany(x => x.Children).Any(x => x.Level > 1)) | ||||
| { | { | ||||
| @@ -220,10 +220,9 @@ namespace Docnet | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets the target URL with respect to the <see cref="T:Docnet.PathSpecification" />. | /// Gets the target URL with respect to the <see cref="T:Docnet.PathSpecification" />. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="pathSpecification">The path specification.</param> | |||||
| /// <param name="navigationContext">The navigation context.</param> | |||||
| /// <returns></returns> | /// <returns></returns> | ||||
| /// <exception cref="System.NotImplementedException"></exception> | |||||
| public override string GetTargetURL(PathSpecification pathSpecification) | |||||
| public override string GetTargetURL(NavigationContext navigationContext) | |||||
| { | { | ||||
| if (_targetURLForHTML == null) | if (_targetURLForHTML == null) | ||||
| { | { | ||||
| @@ -232,7 +231,7 @@ namespace Docnet | |||||
| var toReplace = ".md"; | var toReplace = ".md"; | ||||
| var replacement = ".htm"; | var replacement = ".htm"; | ||||
| if (pathSpecification == PathSpecification.RelativeAsFolder) | |||||
| if (navigationContext.PathSpecification == PathSpecification.RelativeAsFolder) | |||||
| { | { | ||||
| if (!IsIndexElement && !_targetURLForHTML.EndsWith("index.md", StringComparison.InvariantCultureIgnoreCase)) | if (!IsIndexElement && !_targetURLForHTML.EndsWith("index.md", StringComparison.InvariantCultureIgnoreCase)) | ||||
| { | { | ||||