1: /// <summary>
2: /// An extension of <see cref="Grid{T}"/> that adds
3: /// jQuery ActsAsTree functionality.
4: /// </summary>
5: /// <typeparam name="T">The type of the data item being displayed in the grid.</typeparam>
6: public class GridTreeView<T> : Grid<T> where T : class
7: {
8: #region Const Fields
9:
10: /// <summary>
11: /// The index into the HttpContext.Items bag, it tracks whether or not
12: /// the includes for this control have already been written to the the
13: /// response.
14: /// </summary>
15: private const string mItemKey = "GridViewTree.Initialized";
16:
17: /// <summary>
18: /// The default path to the ActsAsTree javascript file.
19: /// </summary>
20: private const string mDefaultJavaScriptPath = "~/Content/jQueryPlugins/ActsAsTreeTable/jquery.acts_as_tree_table.js";
21:
22: /// <summary>
23: /// The default path to the ActsAsTree CSS file.
24: /// </summary>
25: private const string mDefaultCssPath = "~/Content/jQueryPlugins/ActsAsTreeTable/stylesheets/jquery.acts_as_tree_table.css";
26:
27: #endregion
28:
29: #region Private Delegates
30:
31: /// <summary>
32: /// The function that selects the parent ID from an item.
33: /// </summary>
34: private readonly Func<T, string> GetParent;
35:
36: /// <summary>
37: /// The function that selects the ID from an item.
38: /// </summary>
39: private readonly Func<T, string> GetId;
40:
41: #endregion
42:
43: #region Private Fields
44:
45: /// <summary>
46: /// The DOM ID to assign to the grid.
47: /// </summary>
48: private readonly string mGridId;
49:
50: /// <summary>
51: /// The HTML helper class, which is used to resolve URLs.
52: /// </summary>
53: private readonly HtmlHelper mHelper;
54:
55: #endregion
56:
57: #region Public Static Properties
58:
59: /// <summary>
60: /// The path to the JavaScript ActsAsTree file.
61: /// </summary>
62: /// <remarks>
63: /// This shouldn't need to be changed, but just in case, you can override it by changing this property.
64: /// </remarks>
65: public static string JavaScriptPath { get; set; }
66:
67: /// <summary>
68: /// The path to the CSS file that needs to be included for the tree to display correctly.
69: /// </summary>
70: /// <remarks>
71: /// This shouldn't need to be changed, but just in case, you can override it by changing this property.
72: /// </remarks>
73: public static string CssPath { get; set; }
74:
75: #endregion
76:
77: #region Static Constructors
78:
79: /// <summary>
80: /// Initializes the static fields to default values.
81: /// </summary>
82: static GridTreeView()
83: {
84: JavaScriptPath = mDefaultJavaScriptPath;
85: CssPath = mDefaultCssPath;
86: }
87:
88: #endregion
89:
90: #region Public Constructor
91:
92: /// <summary>
93: /// Creates a new GridTreeView class.
94: /// </summary>
95: /// <param name="dataSource"></param>
96: /// <param name="columnBuilder"></param>
97: /// <param name="htmlAttributes"></param>
98: /// <param name="output"></param>
99: /// <param name="helper"></param>
100: /// <param name="idSelector">A delegate that returns an ID from a T.</param>
101: /// <param name="parentIdSelector">A delegate that returns a parent ID from a T.</param>
102: /// <param name="gridId">The ID to assign to the grid.</param>
103: public GridTreeView(string gridId, IEnumerable<T> dataSource, GridColumnBuilder<T> columnBuilder, Func<T, string> idSelector, Func<T, string> parentIdSelector, IDictionary htmlAttributes, TextWriter output, HtmlHelper helper) : base(dataSource, columnBuilder, htmlAttributes, output, (helper == null ? null : helper.ViewContext.HttpContext))
104: {
105: GetParent = parentIdSelector;
106: GetId = idSelector;
107: mGridId = gridId;
108: mHelper = helper;
109:
110: //Override the ID if it has been set
111: HtmlAttributes["id"] = gridId;
112: }
113:
114: #endregion
115:
116: #region Private Methods
117:
118: /// <summary>
119: /// Renders the row with the default ActsAsTree functionality.
120: /// </summary>
121: /// <param name="item"></param>
122: /// <param name="isAlternate"></param>
123: private void RenderActsAsTreeRow(T item, bool isAlternate)
124: {
125: string row = string.Format("<tr class=\"{0} child-of-node-{1}\" id=\"node-{2}\">",
126: isAlternate ? "gridrow_alternate" : "gridrow",
127: GetParent(item), GetId(item));
128:
129: RenderText(row);
130: }
131:
132: /// <summary>
133: /// Writes the tags to include the required ActsAsTree javascript file.
134: /// </summary>
135: private void WriteJavaScriptInclude()
136: {
137: const string script = @"<script type=""text/javascript"" src=""{0}""></script>";
138:
139: RenderText(string.Format(script, ResolveUrl(JavaScriptPath)));
140: }
141:
142: /// <summary>
143: /// Writes the JavaScript to initialize the grid as an ActsAsTree grid.
144: /// </summary>
145: private void WriteActsAsTreeJavaScript()
146: {
147: const string script =
148: @"<script type=""text/javascript"">
149: $(document).ready(function() {{
150: $(""#{0}"").acts_as_tree_table();
151: }});
152: </script>";
153:
154: RenderText(string.Format(script, mGridId));
155: }
156:
157: /// <summary>
158: /// Writes some HTML to do a dynamic CSS include.
159: /// </summary>
160: private void WriteCssInclude()
161: {
162: const string script =
163: @"<script type='text/javascript'>
164: var link=document.createElement('link');
165: link.setAttribute('rel', 'stylesheet');
166: link.setAttribute('type', 'text/css');
167: link.setAttribute('href', '{0}');
168: var head = document.getElementsByTagName('head')[0];
169: head.appendChild(link);
170: </script>";
171:
172: RenderText(string.Format(script, ResolveUrl(CssPath)));
173: }
174:
175: /// <summary>
176: /// Resolves a URL if an HtmlHelper instance is available, otherwise
177: /// just returns the URL.
178: /// </summary>
179: /// <param name="url"></param>
180: /// <returns></returns>
181: private string ResolveUrl(string url)
182: {
183: return mHelper != null ? mHelper.ResolveUrl(url) : url;
184: }
185:
186: #endregion
187:
188: #region Protected Overrides
189:
190: /// <summary>
191: /// Renders the row.
192: /// </summary>
193: /// <param name="item"></param>
194: /// <param name="isAlternate"></param>
195: protected override void RenderRowStart(T item, bool isAlternate)