using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.ComponentModel; using System.Collections.Generic; using System.Xml; namespace DocSite { public partial class DocSiteIndex : System.Web.UI.UserControl, IPostBackEventHandler { #region Public Properties [Browsable(false)] public string SelectedHelpFile { get { return ViewState["_$SelectedHelpFile"] as string ?? string.Empty; } set { if (ViewState["_$SelectedHelpFile"] as string == value) return; ViewState["_$SelectedHelpFile"] = value; OnSelectedHelpFileChanged(EventArgs.Empty); } } [Category("Behavior"), DefaultValue(""), Description("Filters the index so that it only displays entries that are like the specified value.")] public string Filter { get { return ViewState["_$Filter"] as string ?? string.Empty; } set { ViewState["_$Filter"] = value; } } #endregion #region Private / Protected protected static List ItemList { get { if (itemList == null) { lock (sync) { if (itemList == null) itemList = LoadIndex(); } } return itemList; } } protected List FilteredItemList { get { string filter = Filter; List results = new List(); if (string.IsNullOrEmpty(filter) || string.IsNullOrEmpty(filter = filter.Trim())) return results; List list = ItemList; string[] keywords = filter.Split(new char[] { ' ', '.', ',' }, StringSplitOptions.RemoveEmptyEntries); if (keywords.Length == 0) return results; foreach (Item item in list) { List words = new List(item.Name.Split(new char[] { ' ', '.', ',' }, StringSplitOptions.RemoveEmptyEntries)); bool allKeywordsFound = true; foreach (string keyword in keywords) { bool keywordFound = false; foreach (string word in words) { if (word.Equals(keyword, StringComparison.CurrentCultureIgnoreCase)) { keywordFound = true; break; } } if (!keywordFound) { allKeywordsFound = false; break; } } if (allKeywordsFound) results.Add(item); } return results; } } /// /// This field is used by the repeater control's item template to store whether the current item is selected while iterating through the index. /// protected bool currentItemSelected; private static readonly object sync = new object(); private volatile static List itemList; #endregion #region Constructors /// /// Constructs a new instance of the class. /// public DocSiteIndex() { } #endregion #region Methods private static List LoadIndex() { HttpContext context = HttpContext.Current; if (context == null) throw new InvalidOperationException("The LoadIndex method, which initializes the DocSite index, cannot be called outside of a request context."); List items = new List(); XmlReaderSettings settings = new XmlReaderSettings(); settings.IgnoreComments = true; settings.IgnoreProcessingInstructions = true; settings.IgnoreWhitespace = true; using (XmlReader reader = XmlReader.Create( context.Server.MapPath(Properties.Settings.Default.DocSiteIndexXmlSource), settings)) { reader.MoveToContent(); while (reader.Read()) // for each entry { if (!reader.IsStartElement("entry")) continue; string name = reader.GetAttribute("name"); string file = reader.GetAttribute("file"); items.Add(new Item(name, file)); } } items.Sort(delegate(Item item1, Item item2) { return string.Compare(item1.Name, item2.Name, StringComparison.CurrentCulture); }); return items; } protected string GetPostBackClientHyperlink(string file) { return Page.ClientScript.GetPostBackClientHyperlink(this, file, false).Replace('\'', '"'); } #endregion #region Events private readonly object SelectedHelpFileChangedEvent = new object(); /// /// Event raised after the property value has changed. /// [Category("Property Changed")] [Description("Event raised after the SelectedHelpFile property value has changed.")] public event EventHandler SelectedHelpFileChanged { add { lock (SelectedHelpFileChangedEvent) { Events.AddHandler(SelectedHelpFileChangedEvent, value); } } remove { lock (SelectedHelpFileChangedEvent) { Events.RemoveHandler(SelectedHelpFileChangedEvent, value); } } } /// /// Raises the event. /// /// object that provides the arguments for the event. protected virtual void OnSelectedHelpFileChanged(EventArgs e) { EventHandler handler = null; lock (SelectedHelpFileChangedEvent) { handler = (EventHandler)Events[SelectedHelpFileChangedEvent]; } if (handler != null) handler(this, e); } #endregion #region Event Handlers protected void indexSearchButton_Click(object sender, ImageClickEventArgs e) { Filter = indexSearchTextBox.Text; } protected override void OnPreRender(EventArgs e) { indexSearchDiv.Visible = indexFilterCheckbox.Checked; indexRepeater.DataSource = (indexFilterCheckbox.Checked) ? FilteredItemList : ItemList; indexRepeater.DataBind(); index_list_container.Attributes.Add("class", (indexFilterCheckbox.Checked) ? "index_list index_list_filtered" : "index_list"); base.OnPreRender(e); } #endregion #region IPostBackEventHandler Members public void RaisePostBackEvent(string eventArgument) { SelectedHelpFile = eventArgument; } #endregion #region Nested protected struct Item : IEquatable { public string File { get { return file; } } public string Name { get { return name; } } private readonly string file, name; public Item(string name, string file) { this.file = file; this.name = name; } public override bool Equals(object obj) { if (obj is Item) return Equals((Item)obj); else return false; } public override int GetHashCode() { return name.GetHashCode() ^ file.GetHashCode(); } public override string ToString() { return name; } public static bool operator ==(Item t1, Item t2) { return t1.Equals(t2); } public static bool operator !=(Item t1, Item t2) { return !t1.Equals(t2); } #region IEquatable Members public bool Equals(Item other) { return other.file.Equals(file, StringComparison.Ordinal) && other.name.Equals(name, StringComparison.Ordinal); } #endregion } #endregion } }