PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/src/AjaxSnippets/Snippet.cs

http://ajaxsnippets.codeplex.com
C# | 253 lines | 165 code | 34 blank | 54 comment | 16 complexity | 977ff67e05d3d69e69a9b64a287cb8ea MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.UI;
  6. using System.Text;
  7. using System.Reflection;
  8. using System.Web.UI.HtmlControls;
  9. using System.IO;
  10. using System.Text.RegularExpressions;
  11. namespace AjaxSnippets
  12. {
  13. /// <summary>
  14. /// Base class for snippets
  15. /// </summary>
  16. public abstract class Snippet : UserControl
  17. {
  18. /// <summary>
  19. /// TODO: this does not work currently, need to somehow flip this to true if
  20. /// there are child controls of SnippetCallback
  21. /// </summary>
  22. private bool _ContainsCallbacks = false;
  23. private ScriptManager GetScriptManager()
  24. {
  25. return (ScriptManager)Parent.FindControl("ScriptManager");
  26. }
  27. protected override void Render(HtmlTextWriter writer)
  28. {
  29. // Render the contents in <snippet> tag that we can use as a marker
  30. // to strip out the noise that ASP.NET creates which we will not be
  31. // making any use of
  32. if (IsOnSnippetPage) writer.Write("<snippet>");
  33. // Wrap up the snippet in a div with the ClientID of this control
  34. writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
  35. writer.RenderBeginTag(HtmlTextWriterTag.Div);
  36. base.Render(writer);
  37. if (IsOnSnippetPage)
  38. {
  39. RenderCssIncludes(writer);
  40. // HACK: Use reflection to get at ScriptRegistration from ScriptManager
  41. // this holds all the script includes and script blocks ready
  42. // to be pumped out to the browser
  43. ScriptManager sm = GetScriptManager();
  44. List<RegisteredScript> scriptBlocks = null;
  45. List<RegisteredScript> scriptStartupBlocks = null;
  46. if (sm != null)
  47. {
  48. object scriptRegistrations = sm.GetType().GetProperty("ScriptRegistration", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(sm, null);
  49. scriptBlocks = (List<RegisteredScript>)scriptRegistrations.GetType().GetProperty("ScriptBlocks").GetValue(scriptRegistrations, null);
  50. scriptStartupBlocks = (List<RegisteredScript>)scriptRegistrations.GetType().GetProperty("ScriptStartupBlocks").GetValue(scriptRegistrations, null);
  51. }
  52. RenderScriptIncludes(writer, scriptBlocks);
  53. //Make sure we have SnippetManager script registered
  54. RenderSnippetManagerCheckScript(writer);
  55. if (scriptStartupBlocks != null)
  56. {
  57. // Try to remove this component if its already been created in a previous request
  58. RenderComponentRemovalScripts(writer, scriptStartupBlocks);
  59. #region TODO: May have to enumerate descriptors and manually set them up
  60. //foreach (RegisteredScript startupScript in scriptStartupBlocks)
  61. //{
  62. // if (startupScript.Control is IScriptControl)
  63. // {
  64. // IScriptControl scriptControl = (IScriptControl)startupScript.Control;
  65. // IEnumerable<ScriptDescriptor> descriptors = scriptControl.GetScriptDescriptors();
  66. // IEnumerator<ScriptDescriptor> descEnumerator = descriptors.GetEnumerator();
  67. // while (descEnumerator.MoveNext())
  68. // {
  69. // ScriptDescriptor descriptor = descEnumerator.Current;
  70. // }
  71. // }
  72. //}
  73. #endregion
  74. foreach (RegisteredScript startupScript in scriptStartupBlocks)
  75. {
  76. writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/javascript");
  77. writer.AddAttribute("language", "javascript");
  78. writer.RenderBeginTag(HtmlTextWriterTag.Script);
  79. // HACK: Lets replace this and have snippet manager deal with it
  80. writer.Write(startupScript.Script.Replace("Sys.Application.add_init", "AjaxSnippets.SnippetManager.stackFunction"));
  81. writer.RenderEndTag();
  82. }
  83. }
  84. }
  85. if (IsOnSnippetPage) RenderInvokeSnippetRenderedScript(writer);
  86. writer.RenderEndTag();
  87. if (IsOnSnippetPage) writer.Write("</snippet>");
  88. }
  89. /// <summary>
  90. /// TODO: Refactor this to RenderHtmlLinks, attributes for rel and type can be pulled from HtmlLink
  91. /// </summary>
  92. /// <param name="writer"></param>
  93. private void RenderCssIncludes(HtmlTextWriter writer)
  94. {
  95. if (this.Page.Header != null)
  96. {
  97. foreach (Control control in this.Page.Header.Controls)
  98. {
  99. // we expect AJAX Framework scripts to be already rendered since SnippetManager needs it in the hosting page
  100. if (control is HtmlLink)
  101. {
  102. HtmlLink link = (HtmlLink)control;
  103. writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/javascript");
  104. writer.AddAttribute("language", "javascript");
  105. writer.RenderBeginTag(HtmlTextWriterTag.Script);
  106. writer.Write("AjaxSnippets.SnippetManager.loadCss('" + link.Href + "');");
  107. writer.RenderEndTag();
  108. }
  109. }
  110. }
  111. }
  112. private void RenderScriptIncludes(HtmlTextWriter writer, List<RegisteredScript> includes)
  113. {
  114. if (includes != null)
  115. {
  116. foreach (RegisteredScript include in includes)
  117. {
  118. // we expect AJAX Framework scripts to be already rendered since SnippetManager needs it in the hosting page
  119. if (!(include.Control is ScriptManager))
  120. {
  121. writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/javascript");
  122. writer.AddAttribute("language", "javascript");
  123. writer.RenderBeginTag(HtmlTextWriterTag.Script);
  124. writer.Write("AjaxSnippets.SnippetManager.loadScript('" + include.Url + "');");
  125. writer.RenderEndTag();
  126. }
  127. }
  128. }
  129. }
  130. private void RenderComponentRemovalScripts(HtmlTextWriter writer, List<RegisteredScript> scriptStartupBlocks)
  131. {
  132. foreach (RegisteredScript startupScript in scriptStartupBlocks)
  133. {
  134. writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/javascript");
  135. writer.AddAttribute("language", "javascript");
  136. writer.RenderBeginTag(HtmlTextWriterTag.Script);
  137. writer.Write("AjaxSnippets.SnippetManager.removeComponent('" + startupScript.Control.ClientID + "');");
  138. writer.RenderEndTag();
  139. }
  140. }
  141. /// <summary>
  142. /// Renders a script that alerts the user that they need to add the SnippetManager
  143. /// </summary>
  144. /// <param name="writer"></param>
  145. private void RenderSnippetManagerCheckScript(HtmlTextWriter writer)
  146. {
  147. if (_ContainsCallbacks)
  148. {
  149. writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/javascript");
  150. writer.AddAttribute("language", "javascript");
  151. writer.RenderBeginTag(HtmlTextWriterTag.Script);
  152. writer.Write("if($find('SnippetManager') === null) { alert('The SnippetManager control must be added to the page'); }\n");
  153. writer.RenderEndTag();
  154. }
  155. }
  156. /// <summary>
  157. /// Renders a client script block that invokes a client snippetRendered() function if it exists
  158. ///
  159. /// TODO: Might remove this feature, evaluate if this is actually needed
  160. /// </summary>
  161. private void RenderInvokeSnippetRenderedScript(HtmlTextWriter writer)
  162. {
  163. // Invoke the client-side snippetRendered method if any
  164. writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/javascript");
  165. writer.AddAttribute("language", "javascript");
  166. writer.RenderBeginTag(HtmlTextWriterTag.Script);
  167. writer.Write("if(typeof(snippetRendered) !== 'undefined') { snippetRendered('" + this.ID + "') }\n");
  168. writer.RenderEndTag();
  169. }
  170. public bool IsOnSnippetPage
  171. {
  172. get
  173. {
  174. return (this.Page is SnippetPage);
  175. }
  176. }
  177. public override string ToString()
  178. {
  179. if (!IsOnSnippetPage)
  180. return base.ToString();
  181. string result = null;
  182. try
  183. {
  184. StringWriter writer = new StringWriter();
  185. HttpContext.Current.Server.Execute(Page, writer, false);
  186. Regex regEx = new Regex(@"(?<=<snippet>)(.*)(?=</snippet>)", RegexOptions.Singleline);
  187. result = regEx.Match(writer.ToString()).Value;
  188. }
  189. catch (Exception ex)
  190. {
  191. throw ex.GetBaseException();
  192. }
  193. return result;
  194. }
  195. /// <summary>
  196. /// Create a snippet of the given type from the given file
  197. /// </summary>
  198. /// <typeparam name="SnippetType">The Type of the snippet</typeparam>
  199. /// <param name="snippetId">a naming container</param>
  200. /// <param name="virtualPath">The virtual path to the ascx file of this snippet</param>
  201. /// <returns></returns>
  202. public static SnippetType Create<SnippetType>(string snippetId, string virtualPath) where SnippetType : Snippet
  203. {
  204. SnippetPage holder = new SnippetPage();
  205. // HACK: Add a HtmlHead, AjaxControlToolkit controls use this to register CSS
  206. holder.GetType().BaseType.GetField("_header", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(holder, new HtmlHead());
  207. HtmlForm form = new HtmlForm();
  208. holder.Controls.Add(form);
  209. ScriptManager scriptManager = new ScriptManager();
  210. scriptManager.ID = "ScriptManager";
  211. form.Controls.Add(scriptManager);
  212. Snippet snippetControl = (Snippet)holder.LoadControl(virtualPath);
  213. snippetControl.ID = snippetId;
  214. form.Controls.Add(snippetControl);
  215. return (SnippetType)snippetControl;
  216. }
  217. public class SnippetPage : Page{}
  218. }
  219. }