|
|
@@ -31,325 +31,312 @@ using Newtonsoft.Json.Linq; |
|
|
|
|
|
|
|
namespace Docnet |
|
|
|
{ |
|
|
|
public class NavigationLevel : NavigationElement<List<INavigationElement>> |
|
|
|
{ |
|
|
|
private readonly string _rootDirectory; |
|
|
|
|
|
|
|
public NavigationLevel(string rootDirectory) |
|
|
|
: base() |
|
|
|
{ |
|
|
|
this._rootDirectory = rootDirectory; |
|
|
|
this.Value = new List<INavigationElement>(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void Load(JObject dataFromFile) |
|
|
|
{ |
|
|
|
foreach (KeyValuePair<string, JToken> child in dataFromFile) |
|
|
|
{ |
|
|
|
INavigationElement toAdd; |
|
|
|
if (child.Value.Type == JTokenType.String) |
|
|
|
{ |
|
|
|
var nameToUse = child.Key; |
|
|
|
|
|
|
|
var isIndexElement = child.Key == "__index"; |
|
|
|
if (isIndexElement) |
|
|
|
{ |
|
|
|
nameToUse = this.Name; |
|
|
|
} |
|
|
|
|
|
|
|
var childValue = child.Value.ToObject<string>(); |
|
|
|
|
|
|
|
var endsWithWildcards = childValue.EndsWith("**"); |
|
|
|
if (endsWithWildcards) |
|
|
|
{ |
|
|
|
var path = childValue.Replace("**", string.Empty) |
|
|
|
.Replace('\\', Path.DirectorySeparatorChar) |
|
|
|
.Replace('/', Path.DirectorySeparatorChar); |
|
|
|
|
|
|
|
if (!Path.IsPathRooted(path)) |
|
|
|
{ |
|
|
|
path = Path.Combine(_rootDirectory, path); |
|
|
|
} |
|
|
|
|
|
|
|
toAdd = CreateGeneratedLevel(path); |
|
|
|
toAdd.Name = nameToUse; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
toAdd = new SimpleNavigationElement |
|
|
|
{ |
|
|
|
Name = nameToUse, |
|
|
|
Value = childValue, |
|
|
|
IsIndexElement = isIndexElement |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
var subLevel = new NavigationLevel(_rootDirectory) |
|
|
|
{ |
|
|
|
Name = child.Key, |
|
|
|
IsRoot = false |
|
|
|
}; |
|
|
|
subLevel.Load((JObject)child.Value); |
|
|
|
toAdd = subLevel; |
|
|
|
} |
|
|
|
toAdd.ParentContainer = this; |
|
|
|
this.Value.Add(toAdd); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// Collects the search index entries. These are created from simple navigation elements found in this container, which aren't index element. |
|
|
|
/// </summary> |
|
|
|
/// <param name="collectedEntries">The collected entries.</param> |
|
|
|
/// <param name="activePath">The active path currently navigated.</param> |
|
|
|
public override void CollectSearchIndexEntries(List<SearchIndexEntry> collectedEntries, NavigatedPath activePath) |
|
|
|
{ |
|
|
|
activePath.Push(this); |
|
|
|
foreach (var element in this.Value) |
|
|
|
{ |
|
|
|
element.CollectSearchIndexEntries(collectedEntries, activePath); |
|
|
|
} |
|
|
|
activePath.Pop(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// Generates the output for this navigation element |
|
|
|
/// </summary> |
|
|
|
/// <param name="activeConfig">The active configuration to use for the output.</param> |
|
|
|
/// <param name="activePath">The active path navigated through the ToC to reach this element.</param> |
|
|
|
public override void GenerateOutput(Config activeConfig, NavigatedPath activePath) |
|
|
|
{ |
|
|
|
activePath.Push(this); |
|
|
|
int i = 0; |
|
|
|
while (i < this.Value.Count) |
|
|
|
{ |
|
|
|
var element = this.Value[i]; |
|
|
|
element.GenerateOutput(activeConfig, activePath); |
|
|
|
i++; |
|
|
|
} |
|
|
|
activePath.Pop(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// Generates the ToC fragment for this element, which can either be a simple line or a full expanded menu. |
|
|
|
/// </summary> |
|
|
|
/// <param name="navigatedPath">The navigated path to the current element, which doesn't necessarily have to be this element.</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> |
|
|
|
/// <returns></returns> |
|
|
|
public override string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot) |
|
|
|
{ |
|
|
|
var fragments = new List<string>(); |
|
|
|
if (!this.IsRoot) |
|
|
|
{ |
|
|
|
fragments.Add("<li class=\"tocentry\">"); |
|
|
|
} |
|
|
|
if (navigatedPath.Contains(this)) |
|
|
|
{ |
|
|
|
// we're expanded. If we're not root and on the top of the navigated path stack, our index page is the page we're currently generating the ToC for, so |
|
|
|
// we have to mark the entry as 'current' |
|
|
|
if (navigatedPath.Peek() == this && !this.IsRoot) |
|
|
|
{ |
|
|
|
fragments.Add("<ul class=\"current\">"); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fragments.Add("<ul>"); |
|
|
|
} |
|
|
|
|
|
|
|
// 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 indexElement = this.IndexElement; |
|
|
|
if (indexElement == null) |
|
|
|
{ |
|
|
|
fragments.Add(string.Format("{0}{1}</span></li>", elementStartTag, this.Name)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (this.IsRoot) |
|
|
|
{ |
|
|
|
fragments.Add(indexElement.PerformGenerateToCFragment(navigatedPath, relativePathToRoot)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fragments.Add(string.Format("{0}<a href=\"{1}{2}\">{3}</a></span></li>", elementStartTag, relativePathToRoot, HttpUtility.UrlPathEncode(indexElement.TargetURL), |
|
|
|
this.Name)); |
|
|
|
} |
|
|
|
} |
|
|
|
// then the elements in the container. Index elements are skipped here. |
|
|
|
foreach (var element in this.Value) |
|
|
|
{ |
|
|
|
fragments.Add(element.GenerateToCFragment(navigatedPath, relativePathToRoot)); |
|
|
|
} |
|
|
|
fragments.Add("</ul>"); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// just a link |
|
|
|
fragments.Add(string.Format("<span class=\"navigationgroup\"><i class=\"fa fa-caret-right\"></i> <a href=\"{0}{1}\">{2}</a></span>", |
|
|
|
relativePathToRoot, HttpUtility.UrlPathEncode(this.TargetURL), this.Name)); |
|
|
|
} |
|
|
|
if (!this.IsRoot) |
|
|
|
{ |
|
|
|
fragments.Add("</li>"); |
|
|
|
} |
|
|
|
return string.Join(Environment.NewLine, fragments.ToArray()); |
|
|
|
} |
|
|
|
|
|
|
|
private NavigationLevel CreateGeneratedLevel(string path) |
|
|
|
{ |
|
|
|
var root = new NavigationLevel(_rootDirectory) |
|
|
|
{ |
|
|
|
ParentContainer = this |
|
|
|
}; |
|
|
|
|
|
|
|
foreach (var mdFile in Directory.GetFiles(path, "*.md", SearchOption.TopDirectoryOnly)) |
|
|
|
{ |
|
|
|
var name = FindTitleInMdFile(mdFile); |
|
|
|
if (string.IsNullOrWhiteSpace(name)) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
var relativeFilePath = GetRelativePath(_rootDirectory, mdFile); |
|
|
|
|
|
|
|
var item = new SimpleNavigationElement |
|
|
|
{ |
|
|
|
Name = name, |
|
|
|
Value = relativeFilePath, |
|
|
|
ParentContainer = root |
|
|
|
}; |
|
|
|
|
|
|
|
root.Value.Add(item); |
|
|
|
} |
|
|
|
|
|
|
|
foreach (var directory in Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly)) |
|
|
|
{ |
|
|
|
var directoryInfo = new DirectoryInfo(directory); |
|
|
|
|
|
|
|
var subDirectoryNavigationElement = CreateGeneratedLevel(directory); |
|
|
|
|
|
|
|
subDirectoryNavigationElement.Name = directoryInfo.Name; |
|
|
|
subDirectoryNavigationElement.ParentContainer = root; |
|
|
|
|
|
|
|
root.Value.Add(subDirectoryNavigationElement); |
|
|
|
} |
|
|
|
|
|
|
|
return root; |
|
|
|
} |
|
|
|
|
|
|
|
private string GetRelativePath(string origin, string fullPath) |
|
|
|
{ |
|
|
|
var pathUri = new Uri(fullPath); |
|
|
|
|
|
|
|
if (!origin.EndsWith(Path.DirectorySeparatorChar.ToString())) |
|
|
|
{ |
|
|
|
origin += Path.DirectorySeparatorChar; |
|
|
|
} |
|
|
|
|
|
|
|
var folderUri = new Uri(origin); |
|
|
|
return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar)); |
|
|
|
} |
|
|
|
|
|
|
|
private string FindTitleInMdFile(string path) |
|
|
|
{ |
|
|
|
var title = string.Empty; |
|
|
|
|
|
|
|
using (var fileStream = File.OpenRead(path)) |
|
|
|
{ |
|
|
|
using (var streamReader = new StreamReader(fileStream)) |
|
|
|
{ |
|
|
|
var line = string.Empty; |
|
|
|
|
|
|
|
while (string.IsNullOrWhiteSpace(line)) |
|
|
|
{ |
|
|
|
line = streamReader.ReadLine(); |
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(line)) |
|
|
|
{ |
|
|
|
line = line.Trim(); |
|
|
|
|
|
|
|
while (line.StartsWith("#")) |
|
|
|
{ |
|
|
|
line = line.Substring(1).Trim(); |
|
|
|
} |
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(line)) |
|
|
|
{ |
|
|
|
title = line; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return title; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#region Properties |
|
|
|
public override string TargetURL |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
var defaultElement = this.IndexElement; |
|
|
|
if (defaultElement == null) |
|
|
|
{ |
|
|
|
return string.Empty; |
|
|
|
} |
|
|
|
return defaultElement.TargetURL ?? string.Empty; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public SimpleNavigationElement IndexElement |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
var toReturn = this.Value.FirstOrDefault(e => e.IsIndexElement) as SimpleNavigationElement; |
|
|
|
if (toReturn == null) |
|
|
|
{ |
|
|
|
// no index element, add an artificial one. |
|
|
|
var path = string.Empty; |
|
|
|
if (this.ParentContainer != null) |
|
|
|
{ |
|
|
|
path = Path.GetDirectoryName(this.ParentContainer.TargetURL); |
|
|
|
} |
|
|
|
var nameToUse = this.Name.Replace(".", "").Replace('/', '_').Replace("\\", "_").Replace(":", "").Replace(" ", ""); |
|
|
|
if (string.IsNullOrWhiteSpace(nameToUse)) |
|
|
|
{ |
|
|
|
return null; |
|
|
|
} |
|
|
|
toReturn = new SimpleNavigationElement() { ParentContainer = this, Value = string.Format("{0}{1}.md", path, nameToUse), Name = this.Name, IsIndexElement = true }; |
|
|
|
this.Value.Add(toReturn); |
|
|
|
} |
|
|
|
|
|
|
|
return toReturn; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// Gets / sets a value indicating whether this element is the __index element |
|
|
|
/// </summary> |
|
|
|
public override bool IsIndexElement |
|
|
|
{ |
|
|
|
// never an index |
|
|
|
get { return false; } |
|
|
|
set |
|
|
|
{ |
|
|
|
// nop; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public bool IsRoot { get; set; } |
|
|
|
#endregion |
|
|
|
} |
|
|
|
public class NavigationLevel : NavigationElement<List<INavigationElement>> |
|
|
|
{ |
|
|
|
#region Members |
|
|
|
private readonly string _rootDirectory; |
|
|
|
#endregion |
|
|
|
|
|
|
|
public NavigationLevel(string rootDirectory) |
|
|
|
: base() |
|
|
|
{ |
|
|
|
this._rootDirectory = rootDirectory; |
|
|
|
this.Value = new List<INavigationElement>(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void Load(JObject dataFromFile) |
|
|
|
{ |
|
|
|
foreach (KeyValuePair<string, JToken> child in dataFromFile) |
|
|
|
{ |
|
|
|
INavigationElement toAdd; |
|
|
|
if (child.Value.Type == JTokenType.String) |
|
|
|
{ |
|
|
|
var nameToUse = child.Key; |
|
|
|
|
|
|
|
var isIndexElement = child.Key == "__index"; |
|
|
|
if (isIndexElement) |
|
|
|
{ |
|
|
|
nameToUse = this.Name; |
|
|
|
} |
|
|
|
|
|
|
|
var childValue = child.Value.ToObject<string>(); |
|
|
|
if (childValue.EndsWith("**")) |
|
|
|
{ |
|
|
|
var path = childValue.Replace("**", string.Empty) |
|
|
|
.Replace('\\', Path.DirectorySeparatorChar) |
|
|
|
.Replace('/', Path.DirectorySeparatorChar); |
|
|
|
|
|
|
|
if (!Path.IsPathRooted(path)) |
|
|
|
{ |
|
|
|
path = Path.Combine(_rootDirectory, path); |
|
|
|
} |
|
|
|
|
|
|
|
toAdd = CreateGeneratedLevel(path); |
|
|
|
toAdd.Name = nameToUse; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
toAdd = new SimpleNavigationElement |
|
|
|
{ |
|
|
|
Name = nameToUse, |
|
|
|
Value = childValue, |
|
|
|
IsIndexElement = isIndexElement |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
var subLevel = new NavigationLevel(_rootDirectory) |
|
|
|
{ |
|
|
|
Name = child.Key, |
|
|
|
IsRoot = false |
|
|
|
}; |
|
|
|
subLevel.Load((JObject)child.Value); |
|
|
|
toAdd = subLevel; |
|
|
|
} |
|
|
|
toAdd.ParentContainer = this; |
|
|
|
this.Value.Add(toAdd); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// Collects the search index entries. These are created from simple navigation elements found in this container, which aren't index element. |
|
|
|
/// </summary> |
|
|
|
/// <param name="collectedEntries">The collected entries.</param> |
|
|
|
/// <param name="activePath">The active path currently navigated.</param> |
|
|
|
public override void CollectSearchIndexEntries(List<SearchIndexEntry> collectedEntries, NavigatedPath activePath) |
|
|
|
{ |
|
|
|
activePath.Push(this); |
|
|
|
foreach (var element in this.Value) |
|
|
|
{ |
|
|
|
element.CollectSearchIndexEntries(collectedEntries, activePath); |
|
|
|
} |
|
|
|
activePath.Pop(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// Generates the output for this navigation element |
|
|
|
/// </summary> |
|
|
|
/// <param name="activeConfig">The active configuration to use for the output.</param> |
|
|
|
/// <param name="activePath">The active path navigated through the ToC to reach this element.</param> |
|
|
|
public override void GenerateOutput(Config activeConfig, NavigatedPath activePath) |
|
|
|
{ |
|
|
|
activePath.Push(this); |
|
|
|
int i = 0; |
|
|
|
while (i < this.Value.Count) |
|
|
|
{ |
|
|
|
var element = this.Value[i]; |
|
|
|
element.GenerateOutput(activeConfig, activePath); |
|
|
|
i++; |
|
|
|
} |
|
|
|
activePath.Pop(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// Generates the ToC fragment for this element, which can either be a simple line or a full expanded menu. |
|
|
|
/// </summary> |
|
|
|
/// <param name="navigatedPath">The navigated path to the current element, which doesn't necessarily have to be this element.</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> |
|
|
|
/// <returns></returns> |
|
|
|
public override string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot) |
|
|
|
{ |
|
|
|
var fragments = new List<string>(); |
|
|
|
if (!this.IsRoot) |
|
|
|
{ |
|
|
|
fragments.Add("<li class=\"tocentry\">"); |
|
|
|
} |
|
|
|
if (navigatedPath.Contains(this)) |
|
|
|
{ |
|
|
|
// we're expanded. If we're not root and on the top of the navigated path stack, our index page is the page we're currently generating the ToC for, so |
|
|
|
// we have to mark the entry as 'current' |
|
|
|
if (navigatedPath.Peek() == this && !this.IsRoot) |
|
|
|
{ |
|
|
|
fragments.Add("<ul class=\"current\">"); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fragments.Add("<ul>"); |
|
|
|
} |
|
|
|
|
|
|
|
// 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 indexElement = this.IndexElement; |
|
|
|
if (indexElement == null) |
|
|
|
{ |
|
|
|
fragments.Add(string.Format("{0}{1}</span></li>", elementStartTag, this.Name)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (this.IsRoot) |
|
|
|
{ |
|
|
|
fragments.Add(indexElement.PerformGenerateToCFragment(navigatedPath, relativePathToRoot)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fragments.Add(string.Format("{0}<a href=\"{1}{2}\">{3}</a></span></li>", elementStartTag, relativePathToRoot, HttpUtility.UrlPathEncode(indexElement.TargetURL), |
|
|
|
this.Name)); |
|
|
|
} |
|
|
|
} |
|
|
|
// then the elements in the container. Index elements are skipped here. |
|
|
|
foreach (var element in this.Value) |
|
|
|
{ |
|
|
|
fragments.Add(element.GenerateToCFragment(navigatedPath, relativePathToRoot)); |
|
|
|
} |
|
|
|
fragments.Add("</ul>"); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// just a link |
|
|
|
fragments.Add(string.Format("<span class=\"navigationgroup\"><i class=\"fa fa-caret-right\"></i> <a href=\"{0}{1}\">{2}</a></span>", |
|
|
|
relativePathToRoot, HttpUtility.UrlPathEncode(this.TargetURL), this.Name)); |
|
|
|
} |
|
|
|
if (!this.IsRoot) |
|
|
|
{ |
|
|
|
fragments.Add("</li>"); |
|
|
|
} |
|
|
|
return string.Join(Environment.NewLine, fragments.ToArray()); |
|
|
|
} |
|
|
|
|
|
|
|
private NavigationLevel CreateGeneratedLevel(string path) |
|
|
|
{ |
|
|
|
var root = new NavigationLevel(_rootDirectory) |
|
|
|
{ |
|
|
|
ParentContainer = this |
|
|
|
}; |
|
|
|
|
|
|
|
foreach (var mdFile in Directory.GetFiles(path, "*.md", SearchOption.TopDirectoryOnly)) |
|
|
|
{ |
|
|
|
var name = FindTitleInMdFile(mdFile); |
|
|
|
if (string.IsNullOrWhiteSpace(name)) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
var relativeFilePath = Utils.MakeRelativePath(mdFile, _rootDirectory); |
|
|
|
|
|
|
|
var item = new SimpleNavigationElement |
|
|
|
{ |
|
|
|
Name = name, |
|
|
|
Value = relativeFilePath, |
|
|
|
ParentContainer = root |
|
|
|
}; |
|
|
|
|
|
|
|
root.Value.Add(item); |
|
|
|
} |
|
|
|
|
|
|
|
foreach (var directory in Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly)) |
|
|
|
{ |
|
|
|
var directoryInfo = new DirectoryInfo(directory); |
|
|
|
|
|
|
|
var subDirectoryNavigationElement = CreateGeneratedLevel(directory); |
|
|
|
|
|
|
|
subDirectoryNavigationElement.Name = directoryInfo.Name; |
|
|
|
subDirectoryNavigationElement.ParentContainer = root; |
|
|
|
|
|
|
|
root.Value.Add(subDirectoryNavigationElement); |
|
|
|
} |
|
|
|
|
|
|
|
return root; |
|
|
|
} |
|
|
|
|
|
|
|
private string FindTitleInMdFile(string path) |
|
|
|
{ |
|
|
|
var title = string.Empty; |
|
|
|
|
|
|
|
using (var fileStream = File.OpenRead(path)) |
|
|
|
{ |
|
|
|
using (var streamReader = new StreamReader(fileStream)) |
|
|
|
{ |
|
|
|
var line = string.Empty; |
|
|
|
|
|
|
|
while (string.IsNullOrWhiteSpace(line)) |
|
|
|
{ |
|
|
|
line = streamReader.ReadLine(); |
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(line)) |
|
|
|
{ |
|
|
|
line = line.Trim(); |
|
|
|
|
|
|
|
while (line.StartsWith("#")) |
|
|
|
{ |
|
|
|
line = line.Substring(1).Trim(); |
|
|
|
} |
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(line)) |
|
|
|
{ |
|
|
|
title = line; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return title; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#region Properties |
|
|
|
public override string TargetURL |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
var defaultElement = this.IndexElement; |
|
|
|
if (defaultElement == null) |
|
|
|
{ |
|
|
|
return string.Empty; |
|
|
|
} |
|
|
|
return defaultElement.TargetURL ?? string.Empty; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public SimpleNavigationElement IndexElement |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
var toReturn = this.Value.FirstOrDefault(e => e.IsIndexElement) as SimpleNavigationElement; |
|
|
|
if (toReturn == null) |
|
|
|
{ |
|
|
|
// no index element, add an artificial one. |
|
|
|
var path = string.Empty; |
|
|
|
if (this.ParentContainer != null) |
|
|
|
{ |
|
|
|
path = Path.GetDirectoryName(this.ParentContainer.TargetURL); |
|
|
|
} |
|
|
|
var nameToUse = this.Name.Replace(".", "").Replace('/', '_').Replace("\\", "_").Replace(":", "").Replace(" ", ""); |
|
|
|
if (string.IsNullOrWhiteSpace(nameToUse)) |
|
|
|
{ |
|
|
|
return null; |
|
|
|
} |
|
|
|
toReturn = new SimpleNavigationElement() { ParentContainer = this, Value = string.Format("{0}{1}.md", path, nameToUse), Name = this.Name, IsIndexElement = true }; |
|
|
|
this.Value.Add(toReturn); |
|
|
|
} |
|
|
|
|
|
|
|
return toReturn; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// Gets / sets a value indicating whether this element is the __index element |
|
|
|
/// </summary> |
|
|
|
public override bool IsIndexElement |
|
|
|
{ |
|
|
|
// never an index |
|
|
|
get { return false; } |
|
|
|
set |
|
|
|
{ |
|
|
|
// nop; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public bool IsRoot { get; set; } |
|
|
|
#endregion |
|
|
|
} |
|
|
|
} |