blob: db70b80d4350266f4077b5eb6841045ca60a81b3 [file] [log] [blame]
<%@ Page Language="C#" EnableViewState="False" %>
<script runat="server">
//===============================================================================================================
// System : Sandcastle Help File Builder
// File : FillNode.aspx
// Author : Eric Woodruff (Eric@EWoodruff.us)
// Updated : 04/09/2014
// Note : Copyright 2007-2014, Eric Woodruff, All rights reserved
// Compiler: Microsoft C#
//
// This file contains the code used to dynamically load a parent node with its child table of content nodes when
// first expanded.
//
// This code is published under the Microsoft Public License (Ms-PL). A copy of the license should be
// distributed with the code. It can also be found at the project website: https://GitHub.com/EWSoftware/SHFB. This
// notice, the author's name, and all copyright notices must remain intact in all applications, documentation,
// and source files.
//
// Date Who Comments
// ==============================================================================================================
// 06/21/2007 EFW Created the code
// 07/17/2013 EFW Merged code contributed by Procomp Solutions Oy that improves performance for large TOCs by
// using XML serialization and caching.
//===============================================================================================================
private static readonly TocNode[] NoChildNodes = new TocNode[0];
private static readonly object TocLoadSyncObject = new object();
// This is used to contain the serialized table of contents
[XmlRoot("HelpTOC")]
public sealed class TableOfContents
{
[XmlElement("HelpTOCNode")]
public TocNode[] ChildNodes;
[XmlIgnore]
public IDictionary<string, TocNode> NodesById;
internal void IndexNodes()
{
this.NodesById = new Dictionary<string, TocNode>();
AddToIndex(this.NodesById, this.ChildNodes);
}
private static void AddToIndex(IDictionary<string, TocNode> nodesById, TocNode[] nodes)
{
foreach(TocNode node in nodes)
if(!String.IsNullOrEmpty(node.Id))
{
nodesById.Add(node.Id, node);
AddToIndex(nodesById, node.ChildNodes);
}
}
}
// This represents a single node in the table of contents
public sealed class TocNode
{
[XmlAttribute("Id")]
public string Id;
[XmlAttribute("Title")]
public string Title;
[XmlAttribute("Url")]
public string Url;
[XmlElement("HelpTOCNode")]
public TocNode[] ChildNodes;
}
// Load the TOC info and store it in the cache on first use
private TableOfContents GetToc()
{
string tocPath = Server.MapPath("WebTOC.xml");
string tocCacheKey = tocPath;
lock(TocLoadSyncObject)
{
TableOfContents toc = this.Cache[tocCacheKey] as TableOfContents;
if(toc == null)
{
CacheDependency cacheDependency = new CacheDependency(tocPath);
using(XmlReader reader = XmlReader.Create(tocPath))
{
toc = (TableOfContents)new XmlSerializer(typeof(TableOfContents)).Deserialize(reader);
toc.IndexNodes();
}
this.Cache.Insert(tocCacheKey, toc, cacheDependency);
}
return toc;
}
}
// Load the requested node with its children
protected override void Render(HtmlTextWriter writer)
{
StringBuilder sb = new StringBuilder(10240);
TableOfContents toc = this.GetToc();
// The ID to use should be passed in the query string
string expandedId = this.Request.QueryString["Id"];
TocNode expandedNode;
if(toc.NodesById.TryGetValue(expandedId, out expandedNode))
{
foreach(TocNode childNode in expandedNode.ChildNodes ?? NoChildNodes)
{
if(childNode.ChildNodes != null && childNode.ChildNodes.Length != 0)
{
// Write out a parent TOC entry
string childUrl = childNode.Url;
string childTarget;
if(!String.IsNullOrEmpty(childUrl))
childTarget = " target=\"TopicContent\"";
else
{
childUrl = "#";
childTarget = String.Empty;
}
sb.AppendFormat("<div class=\"TreeNode\">\r\n" +
"<img class=\"TreeNodeImg\" onclick=\"javascript: Toggle(this);\" src=\"Collapsed.gif\"/>" +
"<a class=\"UnselectedNode\" onclick=\"javascript: return Expand(this);\" " +
"href=\"{0}\"{1}>{2}</a>\r\n" +
"<div id=\"{3}\" class=\"Hidden\"></div>\r\n" +
"</div>\r\n", HttpUtility.HtmlEncode(childUrl), childTarget, HttpUtility.HtmlEncode(childNode.Title),
childNode.Id);
}
else
{
string childUrl = childNode.Url;
if(String.IsNullOrEmpty(childUrl))
childUrl = "about:blank";
// Write out a TOC entry that has no children
sb.AppendFormat("<div class=\"TreeItem\">\r\n" +
"<img src=\"Item.gif\"/><a class=\"UnselectedNode\" " +
"onclick=\"javascript: return SelectNode(this);\" href=\"{0}\" " +
"target=\"TopicContent\">{1}</a>\r\n" +
"</div>\r\n", HttpUtility.HtmlEncode(childUrl), HttpUtility.HtmlEncode(childNode.Title));
}
}
writer.Write(sb.ToString());
}
else
writer.Write("<b>TOC node not found!</b>");
}
</script>