| @@ -307,6 +307,25 @@ namespace Docnet | |||||
| } | } | ||||
| } | } | ||||
| public UrlFormatting UrlFormatting | |||||
| { | |||||
| get | |||||
| { | |||||
| var urlFormatting = UrlFormatting.None; | |||||
| var urlFormattingAsString = (string)_configData.UrlFormatting; | |||||
| if (!string.IsNullOrWhiteSpace(urlFormattingAsString)) | |||||
| { | |||||
| if (!Enum.TryParse(urlFormattingAsString, true, out urlFormatting)) | |||||
| { | |||||
| urlFormatting = UrlFormatting.None; | |||||
| } | |||||
| } | |||||
| return urlFormatting; | |||||
| } | |||||
| } | |||||
| public NavigationLevel Pages | public NavigationLevel Pages | ||||
| { | { | ||||
| get | get | ||||
| @@ -68,6 +68,8 @@ | |||||
| <Compile Include="SearchIndexEntry.cs" /> | <Compile Include="SearchIndexEntry.cs" /> | ||||
| <Compile Include="SimpleNavigationElement.cs" /> | <Compile Include="SimpleNavigationElement.cs" /> | ||||
| <Compile Include="INavigationElementExtensions.cs" /> | <Compile Include="INavigationElementExtensions.cs" /> | ||||
| <Compile Include="StringExtensions.cs" /> | |||||
| <Compile Include="UrlFormatting.cs" /> | |||||
| <Compile Include="Utils.cs" /> | <Compile Include="Utils.cs" /> | ||||
| </ItemGroup> | </ItemGroup> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| @@ -45,13 +45,7 @@ namespace Docnet | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| var navigationContext = new NavigationContext | |||||
| { | |||||
| MaxLevel = _loadedConfig.MaxLevelInToC, | |||||
| PathSpecification = _loadedConfig.PathSpecification, | |||||
| StripIndexHtm = _loadedConfig.StripIndexHtm | |||||
| }; | |||||
| var navigationContext = new NavigationContext(_loadedConfig.PathSpecification, _loadedConfig.UrlFormatting, _loadedConfig.MaxLevelInToC, _loadedConfig.StripIndexHtm); | |||||
| GeneratePages(navigationContext); | GeneratePages(navigationContext); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -79,7 +73,7 @@ namespace Docnet | |||||
| return null; | return null; | ||||
| } | } | ||||
| var navigationContext = new NavigationContext(config.PathSpecification, config.MaxLevelInToC, config.StripIndexHtm); | |||||
| var navigationContext = new NavigationContext(config.PathSpecification, config.UrlFormatting, config.MaxLevelInToC, config.StripIndexHtm); | |||||
| var indexElement = config.Pages.GetIndexElement(navigationContext); | var indexElement = config.Pages.GetIndexElement(navigationContext); | ||||
| if(indexElement == null) | if(indexElement == null) | ||||
| @@ -4,21 +4,21 @@ | |||||
| { | { | ||||
| public NavigationContext() | public NavigationContext() | ||||
| { | { | ||||
| MaxLevel = 2; | |||||
| this.MaxLevel = 2; | |||||
| } | } | ||||
| public NavigationContext(PathSpecification pathSpecification, int maxLevel, bool stripIndexHtm) | |||||
| public NavigationContext(PathSpecification pathSpecification, UrlFormatting urlFormatting, int maxLevel, bool stripIndexHtm) | |||||
| : this() | : this() | ||||
| { | { | ||||
| PathSpecification = pathSpecification; | PathSpecification = pathSpecification; | ||||
| MaxLevel = maxLevel; | |||||
| UrlFormatting = urlFormatting; | |||||
| MaxLevel = maxLevel; | |||||
| StripIndexHtm = stripIndexHtm; | StripIndexHtm = stripIndexHtm; | ||||
| } | } | ||||
| public PathSpecification PathSpecification { get; set; } | public PathSpecification PathSpecification { get; set; } | ||||
| public int MaxLevel { get; set; } | |||||
| public UrlFormatting UrlFormatting { get; set; } | |||||
| public int MaxLevel { get; set; } | |||||
| public bool StripIndexHtm { get; set; } | public bool StripIndexHtm { get; set; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -305,7 +305,20 @@ namespace Docnet | |||||
| } | } | ||||
| } | } | ||||
| var nameToUse = this.Name.Replace(".", "").Replace('/', '_').Replace("\\", "_").Replace(":", "").Replace(" ", ""); | |||||
| var nameToUse = string.Empty; | |||||
| switch (navigationContext.UrlFormatting) | |||||
| { | |||||
| case UrlFormatting.None: | |||||
| // Backwards compatibility mode | |||||
| nameToUse = this.Name.Replace(".", "").Replace('/', '_').Replace("\\", "_").Replace(":", "").Replace(" ", ""); | |||||
| break; | |||||
| default: | |||||
| nameToUse = this.Name.ApplyUrlFormatting(navigationContext.UrlFormatting); | |||||
| break; | |||||
| } | |||||
| if (string.IsNullOrWhiteSpace(nameToUse)) | if (string.IsNullOrWhiteSpace(nameToUse)) | ||||
| { | { | ||||
| return null; | return null; | ||||
| @@ -226,14 +226,18 @@ namespace Docnet | |||||
| { | { | ||||
| if (_targetURLForHTML == null) | if (_targetURLForHTML == null) | ||||
| { | { | ||||
| _targetURLForHTML = (this.Value ?? string.Empty); | |||||
| var toReplace = ".md"; | |||||
| var toReplace = "mdext"; | |||||
| var replacement = ".htm"; | var replacement = ".htm"; | ||||
| var value = (this.Value ?? string.Empty); | |||||
| // Replace with custom extension because url formatting might optimize the extension | |||||
| value = value.Replace(".md", toReplace); | |||||
| _targetURLForHTML = value.ApplyUrlFormatting(navigationContext.UrlFormatting); | |||||
| if (navigationContext.PathSpecification == PathSpecification.RelativeAsFolder) | if (navigationContext.PathSpecification == PathSpecification.RelativeAsFolder) | ||||
| { | { | ||||
| if (!IsIndexElement && !_targetURLForHTML.EndsWith("index.md", StringComparison.InvariantCultureIgnoreCase)) | |||||
| if (!IsIndexElement && !_targetURLForHTML.EndsWith($"index{toReplace}", StringComparison.InvariantCultureIgnoreCase)) | |||||
| { | { | ||||
| replacement = "/index.htm"; | replacement = "/index.htm"; | ||||
| } | } | ||||
| @@ -0,0 +1,57 @@ | |||||
| using System; | |||||
| using System.Text.RegularExpressions; | |||||
| namespace Docnet | |||||
| { | |||||
| internal static class StringExtensions | |||||
| { | |||||
| public static string ApplyUrlFormatting(this string value, UrlFormatting urlFormatting) | |||||
| { | |||||
| var finalValue = string.Empty; | |||||
| string replacementValue = null; | |||||
| switch (urlFormatting) | |||||
| { | |||||
| case UrlFormatting.None: | |||||
| finalValue = value; | |||||
| break; | |||||
| case UrlFormatting.Strip: | |||||
| replacementValue = string.Empty; | |||||
| break; | |||||
| case UrlFormatting.Dashes: | |||||
| replacementValue = "-"; | |||||
| break; | |||||
| default: | |||||
| throw new ArgumentOutOfRangeException(nameof(urlFormatting), urlFormatting, null); | |||||
| } | |||||
| if (replacementValue != null) | |||||
| { | |||||
| var doubleReplacementValue = replacementValue + replacementValue; | |||||
| var regEx = new Regex("[^a-zA-Z0-9 -]"); | |||||
| var splitted = value.Split(new[] { "/", "\\" }, StringSplitOptions.RemoveEmptyEntries); | |||||
| for(var i = 0; i < splitted.Length; i++) | |||||
| { | |||||
| var splittedValue = splitted[i]; | |||||
| splittedValue = regEx.Replace(splittedValue, replacementValue).Replace(" ", replacementValue); | |||||
| if (!string.IsNullOrEmpty(replacementValue)) | |||||
| { | |||||
| while (splittedValue.Contains(doubleReplacementValue)) | |||||
| { | |||||
| splittedValue = splittedValue.Replace(doubleReplacementValue, replacementValue); | |||||
| } | |||||
| } | |||||
| splitted[i] = splittedValue.ToLower(); | |||||
| } | |||||
| finalValue = string.Join("/", splitted); | |||||
| } | |||||
| return finalValue; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| namespace Docnet | |||||
| { | |||||
| public enum UrlFormatting | |||||
| { | |||||
| None, | |||||
| Strip, | |||||
| Dashes | |||||
| } | |||||
| } | |||||