| <%@ 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> |