using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections;
namespace IlluminatedIndustries.WebCustomControls
{
/// <summary>
/// Site Compass Classes - The class generates and maintains a ASP .NET cookie crumb system
/// </summary>
[
Designer("IlluminatedIndustries.WebCustomControls.SiteCompassDesigner, SiteCompass"),
DefaultProperty("DisplayTitle"),
ToolboxData("<{0}:SiteCompass runat=server></{0}:SiteCompass>")
]
public class SiteCompass : System.Web.UI.WebControls.WebControl
{
#region Class Variable Declarations
public enum CompassStyles
{
VerticalHTML,
HorizonatalHTML,
DHTMLMenu
}
private CompassStyles _compassStyle = CompassStyles.HorizonatalHTML;
public enum ItemLinkTargets
{
_self,
_top,
_blank,
_parent
}
private ItemLinkTargets _itemLinkTarget = ItemLinkTargets._self;
public enum ItemLinkOverrideTargets
{
none,
_self,
_top,
_blank,
_parent
}
private ItemLinkOverrideTargets _overrideTarget = ItemLinkOverrideTargets.none;
public enum Modes
{
Normal,
DisplayOnly
}
private Modes _mode = Modes.Normal;
private bool _caseSensitiveUrlComparison = false;
private bool _linkLastItem = false;
private bool _suppressIcons = false;
private int _maxItems = 8;
private string _cssClassLink = string.Empty;
private string _currentPageIndicator = string.Empty;
private string _displayTitle = string.Empty;
private string _divName = string.Empty;
private string _itemIconAlt = string.Empty;
private string _itemSeperator = " >> ";
private string _itemIconPath = string.Empty;
private string _sessionKey = "EE517D2A-DE98-42b4-B64F-DF8967BF210E";
private string _prefixCode = string.Empty;
private string _postfixCode = string.Empty;
#endregion
#region Appearance Property Accessors
[
Bindable(true),
Category("Appearance"),
DefaultValue(CompassStyles.HorizonatalHTML),
Description("The style of compass to use. If you choose DHTML menu ensure you deploy (and reference it within your code) the siteCompassDHTML.js dependency file with your webproject."),
]
public CompassStyles CompassStyle
{
get { return this._compassStyle; }
set { this._compassStyle = value; }
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(" >> "),
Description("The seperator between Site Compass items (ensure that you assign spaces if required).")
]
public string ItemSeperator
{
get { return this._itemSeperator; }
set { this._itemSeperator = value; }
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description(@"Any HTML code entered here will be rendered
within the compass DIV before the compass item code (within 'a'
tags) when rendering under vertical or horizontal html. In
DHTML mode use this field to enter a menu title.")
]
public string PrefixCode
{
get { return this._prefixCode; }
set { this._prefixCode = value; }
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("Any HTML code entered here will be rendered within the compass DIV after the compass code (within <a> tags)")
]
public string PostfixCode
{
get { return this._postfixCode; }
set { this._postfixCode = value; }
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("This is the class name to use for the links in the compass, this will allow you to set specific hover etc css properties")
]
public string CssClassLink
{
get { return this._cssClassLink; }
set { this._cssClassLink = value; }
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("Set this value to show it agaisnt the current page.")
]
public string CurrentPageIndicator
{
get { return this._currentPageIndicator; }
set { this._currentPageIndicator = value; }
}
#endregion
#region Compass Item Property Accessors
[
Bindable(true),
Category("Compass Item"),
DefaultValue(""),
Description("The text used on the Site Compass item to identify the current page.")
]
public string DisplayTitle
{
get { return this._displayTitle; }
set { this._displayTitle = value; }
}
[
Bindable(true),
Category("Compass Item"),
DefaultValue(""),
Description("This is the \"alt\" value that will be assigned to your item icon.")
]
public string IconAlt
{
get { return this._itemIconAlt; }
set { this._itemIconAlt = value; }
}
[
Bindable(true),
Category("Compass Item"),
DefaultValue(""),
Description("Path to the icon to use for this pages compass item, if not set no image will be displayed. This path must be relative to the server root.")
]
public string IconPath
{
get { return this._itemIconPath; }
set { this._itemIconPath = value; }
}
[
Bindable(true),
Category("Compass Item"),
DefaultValue(ItemLinkTargets._self),
Description("The target attribute of the compass item link.")
]
public ItemLinkTargets LinkTarget
{
get { return this._itemLinkTarget; }
set { this._itemLinkTarget = value; }
}
#endregion
#region Behavior Property Accessors
[
Bindable(true),
Category("Behavior"),
DefaultValue(8),
Description("The maximum number of items to display in the Site Compass control. Set to 0 to display all items in the current compass")
]
public int MaxItems
{
get { return this._maxItems; }
set { this._maxItems = value; }
}
[
Bindable(true),
Category("Behavior"),
DefaultValue(false),
Description("Indicates if the last item in the Site Compass is linked.")
]
public bool LinkLastItem
{
get { return this._linkLastItem; }
set { this._linkLastItem = value; }
}
[
Bindable(true),
Category("Behavior"),
DefaultValue(false),
Description("If set to true cases will be ignored when comparing compass items.")
]
public bool CaseSensitiveUrlComparison
{
get { return this._caseSensitiveUrlComparison; }
set { this._caseSensitiveUrlComparison = value; }
}
[
Bindable(true),
Category("Behavior"),
DefaultValue(Modes.Normal),
Description("Set to \"display only\" mode to render the current items in the compass without adding to it.")
]
public Modes Mode
{
get { return this._mode; }
set { this._mode = value; }
}
[
Bindable(true),
Category("Behavior"),
DefaultValue(false),
Description("Set this value to true if you want to prevent item icons from being displayed even if an item has one allocated.")
]
public bool SuppressIcons
{
get { return this._suppressIcons; }
set { this._suppressIcons = value; }
}
[
Bindable(true),
Category("Behavior"),
DefaultValue(""),
Description("This value is assigned as the \"name\" attribute of the DIV containing the compass. This is useful if you want to refer to the DIV in your own javascripts.")
]
public string DivName
{
get { return this._divName; }
set { this._divName = value; }
}
[
Bindable(true),
Category("Behavior"),
DefaultValue(ItemLinkOverrideTargets.none),
Description("Set this value to override any target attribute currently set in compass items (this does not change the item itself).")
]
public ItemLinkOverrideTargets OverrideTarget
{
get { return this._overrideTarget; }
set { this._overrideTarget = value; }
}
#endregion
#region Misc Property Accessors
[
Bindable(true),
Category("Misc"),
DefaultValue("EE517D2A-DE98-42b4-B64F-DF8967BF210E"),
Description("A unique key to identify the compass data in the current session.")
]
public string SessionKey
{
get { return this._sessionKey; }
set { this._sessionKey = value; }
}
#endregion
#region Disabled Property Accessors
//These properties are overridden to prevent them
//from being displayed in the designer properties
//are they are not relevant to the control but come
//as default through the inheritance from
//System.Web.UI.WebControls.WebControl
//
//I wasnt entirely happy with the way the HtmlTextWriter
//class creates HTML when using these properties so I
//decided to force the use of stylesheets
[Browsable(false)]
public override FontInfo Font
{
get { return base.Font; }
}
[Browsable(false)]
public override System.Drawing.Color ForeColor
{
get { return base.ForeColor; }
set { base.ForeColor = value; }
}
[Browsable(false)]
public override System.Drawing.Color BackColor
{
get { return base.BackColor; }
set { base.BackColor = value; }
}
[Browsable(false)]
public override System.Drawing.Color BorderColor
{
get { return base.BorderColor; }
set { base.BorderColor = value; }
}
[Browsable(false)]
public override BorderStyle BorderStyle
{
get { return base.BorderStyle; }
set { base.BorderStyle = value; }
}
[Browsable(false)]
public override Unit BorderWidth
{
get { return base.BorderWidth; }
set { base.BorderWidth = value; }
}
[Browsable(false)]
public override Unit Height
{
get { return base.Height; }
set { base.Height = value; }
}
[Browsable(false)]
public override Unit Width
{
get { return base.Width; }
set { base.Width = value; }
}
#endregion
#region Generic Overrides
/// <summary>
/// Render this control to the output parameter specified.
/// </summary>
/// <param name="output"> The HTML writer to write out to </param>
protected override void Render(HtmlTextWriter output)
{
BuildCompassCache();
switch (this.CompassStyle)
{
case CompassStyles.HorizonatalHTML:
case CompassStyles.VerticalHTML:
GenerateCompass_HTML(output, false);
break;
case CompassStyles.DHTMLMenu:
GenerateCompass_DHTMLMenu(output, false);
break;
}
}
#endregion
#region Implementation
/// <summary>
/// Builds the Site Compass item cache
/// </summary>
private void BuildCompassCache()
{
//If the control is in DisplayOnly mode there
//is no need to adjust or change the session
//data so simply return out
if (this.Mode == Modes.DisplayOnly)
{
return;
}
//declare an arraylist to hold the compass data
ArrayList compassData;
//if the session data is null then instantiate
//compassData as a new arraylist.
if (Page.Session[this.SessionKey] == null)
{
compassData = new ArrayList();
}
//if the session data contains compass data then
//instantiate the compassData object with it
else
{
compassData = (ArrayList)Page.Session[this.SessionKey];
}
//generate a new compass item object using the
//parameters from the designer
CompassItem newItem = new CompassItem();
newItem.RawUrl = Page.Request.RawUrl;
newItem.DisplayTitle = this.DisplayTitle;
newItem.IconPath = this.IconPath;
newItem.IconAlt = this.IconAlt;
newItem.Target = this.LinkTarget.ToString();
//set the value of the static variable that
//indicates if object searches are case
//sensitive
CompassItem.CaseSensitiveUrlComparison = this.CaseSensitiveUrlComparison;
//check if the newItem exists in the current
//compass data this is possible as CompassItem
//has an overriden .equals()
if (compassData.Contains(newItem))
{
int index = compassData.IndexOf(newItem) + 1;
int count = compassData.Count - index;
compassData.RemoveRange(index, count);
}
//if the current item doesnt exist simply
//add it to the end
else
{
compassData.Add(newItem);
}
//place the compass data back into
//the session
Page.Session[this.SessionKey] = compassData;
}
/// <summary>
/// Generates compass HTML for both vertical and horizontal styles
///
/// This demonstrates usage of HtmlTextWriter
/// </summary>
/// <param name="output">HtmlTextWriter to write into</param>
public void GenerateCompass_HTML(HtmlTextWriter output, bool designer)
{
//declare and arraylist to contain the compass data
//to process and instantiate with the data to render
ArrayList compassData = GetRenderData(designer);
//open the div tag to contain the compass
//add set the base div parameters
output.WriteBeginTag("div");
//write the div name attribute if set
if (this.DivName.Trim().Length > 0)
{
output.WriteAttribute("name", this._divName);
}
//write the div css class attribute if set
if (this.CssClass.Trim().Length > 0)
{
output.WriteAttribute("class", this.CssClass);
}
//close the div tag
output.Write(HtmlTextWriter.TagRightChar);
//write line for code clarity
output.WriteLine();
//Check if the control has prefix code and write if required
if (this.PrefixCode.Trim().Length > 0)
{
output.WriteFullBeginTag("a");
output.Write(this.PrefixCode);
output.WriteEndTag("a");
output.WriteLine();
}
//cycle through each compass item and write this into
//the output HtmlTextWriter
foreach (CompassItem loopItem in compassData)
{
//get the index of the current item to prevent
//constantly querying the .IndexOf function
int itemIndex = compassData.IndexOf(loopItem);
//write img tag if available and not suppressed
if ((loopItem.IconPath.Trim().Length > 0) && (this.SuppressIcons == false))
{
output.WriteBeginTag("img");
output.WriteAttribute("src", loopItem.IconPath);
output.WriteAttribute("alt", loopItem.IconAlt);
output.Write(HtmlTextWriter.SelfClosingTagEnd);
}
//check if we are currently working on the last item in
//the compass if so render this without a link unless
//otherwise specified through the LinkLastItem property
if ((itemIndex == compassData.Count - 1) && (this.LinkLastItem == false))
{
//Add the seperator characters only if rendering a
//verticalHTML compass
if (this.CompassStyle == CompassStyles.VerticalHTML)
{
output.WriteFullBeginTag("a");
output.Write(this.ItemSeperator);
output.WriteEndTag("a");
}
//write the display title without a href link
output.WriteFullBeginTag("a");
output.Write(loopItem.DisplayTitle);
}
//create a linked compass item
else
{
//Add the seperator characters only if rendering a
//verticalHTML compass
if (this.CompassStyle == CompassStyles.VerticalHTML)
{
output.WriteFullBeginTag("a");
output.Write(this.ItemSeperator);
output.WriteEndTag("a");
}
//write the item link and display title into the
//the output stream
output.WriteBeginTag("a");
output.WriteAttribute("class", this.CssClassLink);
output.WriteAttribute("href", loopItem.RawUrl);
//only write the target attribute if it isnt overridden
if (this.OverrideTarget == ItemLinkOverrideTargets.none)
{
output.WriteAttribute("target", loopItem.Target);
}
else
{
output.WriteAttribute("target", this.OverrideTarget.ToString());
}
output.Write(HtmlTextWriter.TagRightChar);
output.Write(loopItem.DisplayTitle);
}
//write the currentpageindicator value if this is the last item
//and the indicator has been assigned a value
if ((compassData.IndexOf(loopItem) == compassData.Count - 1) && (this.CurrentPageIndicator.Trim().Length > 0))
{
output.Write(this.CurrentPageIndicator);
}
//close the item <a> tag
output.WriteEndTag("a");
//Add the seperator unless we are rendering
//the last item or a verticalHTML compass (in
//case just write a <br>)
if ((itemIndex < compassData.Count - 1) && (this.CompassStyle != CompassStyles.VerticalHTML))
{
output.WriteFullBeginTag("a");
output.Write(this.ItemSeperator);
output.WriteEndTag("a");
}
else
{
output.WriteFullBeginTag("br");
}
//write line for code clarity
output.WriteLine();
} //END - foreach (CompassItem loopItem in compassData)
//Check if the control has a postfix entered
if (this.PostfixCode.Trim().Length > 0)
{
output.WriteFullBeginTag("a");
output.Write(this.PostfixCode);
output.WriteEndTag("a");
}
output.WriteEndTag("div");
}
/// <summary>
/// Generate compass HTML for a DHTML drop down menu
///
/// This demonstrates using strings instead of HtmlTextWriter
/// </summary>
/// <returns></returns>
public void GenerateCompass_DHTMLMenu(HtmlTextWriter output, bool designer)
{
//declare and arraylist to contain the compass data
//to process and instantiate with the data to render
ArrayList compassData = GetRenderData(designer);
output.WriteBeginTag("div");
output.WriteAttribute("class", "menuBar");
output.Write(HtmlTextWriter.TagRightChar);
output.WriteBeginTag("a");
output.WriteAttribute("class", "menuButton");
output.WriteAttribute("href", "");
output.WriteAttribute("onclick", "return buttonClick(event, 'menuCompassItem');");
output.WriteAttribute("onmouseover", "buttonMouseover(event, 'menuCompassItem');");
output.Write(HtmlTextWriter.TagRightChar);
output.Write(this.PrefixCode);
output.WriteEndTag("a");
output.WriteEndTag("div");
output.WriteBeginTag("div");
output.WriteAttribute("id", "menuCompassItem");
output.WriteAttribute("class", "menu");
output.WriteAttribute("onmouseover", "menuMouseover(event)");
output.Write(HtmlTextWriter.TagRightChar);
foreach (CompassItem loopItem in compassData)
{
output.WriteBeginTag("a");
output.WriteAttribute("class", "menuItem");
output.WriteAttribute("href", loopItem.RawUrl);
//only write the target attribute if it isnt overridden
if (this.OverrideTarget == ItemLinkOverrideTargets.none)
{
output.WriteAttribute("target", loopItem.Target);
}
else
{
output.WriteAttribute("target", this.OverrideTarget.ToString());
}
output.Write(HtmlTextWriter.TagRightChar);
if (loopItem.IconPath.Trim().Length > 0)
{
output.WriteBeginTag("img");
output.WriteAttribute("src", loopItem.IconPath);
output.WriteAttribute("alt", loopItem.IconAlt);
output.Write(HtmlTextWriter.SelfClosingTagEnd);
}
output.Write(loopItem.DisplayTitle);
//write the currentpageindicator value if this is the last item
//and the indicator has been assigned a value
if ((compassData.IndexOf(loopItem) == compassData.Count - 1) && (this.CurrentPageIndicator.Trim().Length > 0))
{
output.Write(this.CurrentPageIndicator);
}
output.WriteEndTag("a");
}
output.WriteEndTag("div");
}
/// <summary>
/// Simple function to retrieve compass data from the session
/// or create a dummy one for the VS .NET designer.
/// </summary>
/// <param name="designer"></param>
/// <returns></returns>
private ArrayList GetRenderData(bool designer)
{
ArrayList compassData;
//check if VS .NET designer is calling the code
//if it is then create a dummy compassData array
//otherwise get the real data from the session
if (designer)
{
compassData = new ArrayList();
for(int i=0; i<this.MaxItems; i++)
{
CompassItem designerItem = new CompassItem();
designerItem.DisplayTitle = string.Format("Link{0}", i);
designerItem.IconPath = this.IconPath;
designerItem.IconAlt = this.IconAlt;
compassData.Add(designerItem);
}
}
else
{
compassData = (ArrayList)Page.Session[this.SessionKey];
//check that the total items does not
//exceed the maximum, remove from the
//start if it does, this doesnt effect
//the session data which will allow a
//user to back track
if ((compassData.Count > this.MaxItems) && (this.MaxItems != 0))
{
ArrayList strippedData = new ArrayList();
for (int index = compassData.Count - this.MaxItems; index < compassData.Count; index++)
{
strippedData.Add(compassData[index]);
}
return strippedData;
}
}
return compassData;
}
/// <summary>
/// Resets and removes all current compass items
/// </summary>
public void ResetCompass()
{
Page.Session[this.SessionKey] = new ArrayList();
}
/// <summary>
/// Resets the compass with an array list of compass items
/// </summary>
/// <param name="compassData"></param>
public void ResetCompass(ArrayList compassData)
{
Page.Session[this.SessionKey] = compassData;
}
/// <summary>
/// Resets the compass to the given compass item
/// </summary>
/// <param name="item"></param>
public void ResetCompass(CompassItem item)
{
ArrayList compassData = new ArrayList();
compassData.Add(item);
Page.Session[this.SessionKey] = compassData;
}
/// <summary>
/// Retrieves the compass item at the given index (first occurence), returns null if not available
/// </summary>
/// <param name="index"></param>
public CompassItem GetCompassItemAt(int index)
{
ArrayList compassData = (ArrayList)Page.Session[this.SessionKey];
if (index > compassData.Count - 1)
{
return null;
}
return (CompassItem)compassData[index];
}
#endregion
}
}