/DNN Platform/Modules/DDRMenu/TemplateEngine/TemplateDefinition.cs

https://github.com/sleupold/Dnn.Platform · C# · 332 lines · 300 code · 30 blank · 2 comment · 30 complexity · 12f77e5dab0f189a5fe1ae3a70d39150 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. using System.Web;
  7. using System.Web.Caching;
  8. using System.Web.UI;
  9. using System.Web.UI.HtmlControls;
  10. using System.Xml;
  11. using DotNetNuke.Common;
  12. using DotNetNuke.Web.DDRMenu.DNNCommon;
  13. namespace DotNetNuke.Web.DDRMenu.TemplateEngine
  14. {
  15. public class TemplateDefinition
  16. {
  17. internal string Folder;
  18. internal string TemplatePath;
  19. internal string TemplateVirtualPath;
  20. internal string TemplateHeadPath;
  21. internal readonly List<string> ScriptKeys = new List<string>();
  22. internal readonly Dictionary<string, string> Scripts = new Dictionary<string, string>();
  23. internal readonly List<string> StyleSheets = new List<string>();
  24. internal readonly List<ClientOption> DefaultClientOptions = new List<ClientOption>();
  25. internal readonly List<TemplateArgument> DefaultTemplateArguments = new List<TemplateArgument>();
  26. internal ITemplateProcessor Processor;
  27. public List<ClientOption> ClientOptions = new List<ClientOption>();
  28. public List<TemplateArgument> TemplateArguments = new List<TemplateArgument>();
  29. private readonly Regex regexLinks =
  30. new Regex(
  31. "( (href|src)=['\"]?)(?!http:|ftp:|mailto:|file:|javascript:|/)([^'\">]+['\">])",
  32. RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
  33. internal static TemplateDefinition FromName(string templateName, string manifestName)
  34. {
  35. var manifestUrl = new PathResolver(null).Resolve(
  36. templateName + "/" + manifestName,
  37. PathResolver.RelativeTo.Container,
  38. PathResolver.RelativeTo.Skin,
  39. PathResolver.RelativeTo.Portal,
  40. PathResolver.RelativeTo.Module,
  41. PathResolver.RelativeTo.Dnn);
  42. return FromManifest(manifestUrl);
  43. }
  44. internal static TemplateDefinition FromManifest(string manifestUrl)
  45. {
  46. var httpContext = HttpContext.Current;
  47. var cache = httpContext.Cache;
  48. var manifestPath = httpContext.Server.MapPath(manifestUrl);
  49. var baseDef = cache[manifestPath] as TemplateDefinition;
  50. if (baseDef == null)
  51. {
  52. baseDef = new TemplateDefinition {Folder = Path.GetDirectoryName(manifestUrl)};
  53. var xml = new XmlDocument();
  54. xml.Load(manifestPath);
  55. var resolver = new PathResolver(baseDef.Folder);
  56. // ReSharper disable PossibleNullReferenceException
  57. foreach (XmlNode node in xml.DocumentElement.ChildNodes)
  58. // ReSharper restore PossibleNullReferenceException
  59. {
  60. if (node.NodeType == XmlNodeType.Element)
  61. {
  62. var elt = (XmlElement)node;
  63. switch (elt.LocalName)
  64. {
  65. case "template":
  66. baseDef.TemplateVirtualPath = GetResolvedPath(elt, resolver);
  67. baseDef.TemplatePath = httpContext.Server.MapPath(baseDef.TemplateVirtualPath);
  68. break;
  69. case "templateHead":
  70. baseDef.TemplateHeadPath = httpContext.Server.MapPath(GetResolvedPath(elt, resolver));
  71. break;
  72. case "scripts":
  73. foreach (XmlElement scriptElt in elt.GetElementsByTagName("script"))
  74. {
  75. var jsObject = scriptElt.GetAttribute("jsObject");
  76. var scriptPath = String.IsNullOrEmpty(scriptElt.InnerText.Trim())
  77. ? ""
  78. : Globals.ResolveUrl(GetResolvedPath(scriptElt, resolver));
  79. var key = String.IsNullOrEmpty(jsObject) ? scriptPath : jsObject;
  80. var script = CreateScript(jsObject, scriptPath);
  81. if (!String.IsNullOrEmpty(script))
  82. {
  83. baseDef.ScriptKeys.Add(key);
  84. baseDef.Scripts.Add(key, script);
  85. }
  86. }
  87. break;
  88. case "stylesheets":
  89. foreach (XmlElement cssElt in elt.GetElementsByTagName("stylesheet"))
  90. {
  91. var cssPath = Globals.ResolveUrl(GetResolvedPath(cssElt, resolver));
  92. baseDef.StyleSheets.Add(cssPath);
  93. }
  94. break;
  95. case "defaultClientOptions":
  96. foreach (XmlElement optionElt in elt.GetElementsByTagName("clientOption"))
  97. {
  98. var optionName = optionElt.GetAttribute("name");
  99. var optionType = optionElt.GetAttribute("type");
  100. var optionValue = optionElt.GetAttribute("value");
  101. if (String.IsNullOrEmpty(optionType))
  102. {
  103. optionType = "passthrough";
  104. }
  105. switch (optionType)
  106. {
  107. case "number":
  108. baseDef.DefaultClientOptions.Add(new ClientNumber(optionName, optionValue));
  109. break;
  110. case "boolean":
  111. baseDef.DefaultClientOptions.Add(new ClientBoolean(optionName, optionValue));
  112. break;
  113. case "string":
  114. baseDef.DefaultClientOptions.Add(new ClientString(optionName, optionValue));
  115. break;
  116. default:
  117. baseDef.DefaultClientOptions.Add(new ClientOption(optionName, optionValue));
  118. break;
  119. }
  120. }
  121. break;
  122. case "defaultTemplateArguments":
  123. foreach (XmlElement argElt in elt.GetElementsByTagName("templateArgument"))
  124. {
  125. var argName = argElt.GetAttribute("name");
  126. var argValue = argElt.GetAttribute("value");
  127. baseDef.DefaultTemplateArguments.Add(new TemplateArgument(argName, argValue));
  128. }
  129. break;
  130. }
  131. }
  132. }
  133. foreach (var processor in DNNAbstract.SupportedTemplateProcessors())
  134. {
  135. if (processor.LoadDefinition(baseDef))
  136. {
  137. baseDef.Processor = processor;
  138. break;
  139. }
  140. }
  141. if (baseDef.Processor == null)
  142. {
  143. throw new ApplicationException(String.Format("Can't find processor for manifest {0}", manifestPath));
  144. }
  145. cache.Insert(manifestPath, baseDef, new CacheDependency(new[] {manifestPath, baseDef.TemplatePath}));
  146. }
  147. var result = baseDef.Clone();
  148. result.Reset();
  149. return result;
  150. }
  151. private static string GetResolvedPath(XmlNode scriptElt, PathResolver pathResolver)
  152. {
  153. return pathResolver.Resolve(
  154. scriptElt.InnerText.Trim(),
  155. PathResolver.RelativeTo.Manifest,
  156. PathResolver.RelativeTo.Skin,
  157. PathResolver.RelativeTo.Module,
  158. PathResolver.RelativeTo.Portal,
  159. PathResolver.RelativeTo.Dnn);
  160. }
  161. private static string CreateScript(string jsObject, string scriptPath)
  162. {
  163. string result;
  164. jsObject = jsObject ?? "";
  165. if (String.IsNullOrEmpty(scriptPath))
  166. {
  167. var scheme = HttpContext.Current.Request.Url.Scheme;
  168. switch (jsObject)
  169. {
  170. case "jQuery":
  171. case "DDRjQuery":
  172. scriptPath = DNNAbstract.RequestJQuery()
  173. ? ""
  174. : (scheme + "://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js");
  175. break;
  176. case "jQuery.ui":
  177. scriptPath = scheme + "://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js";
  178. break;
  179. default:
  180. throw new ApplicationException(String.Format("Can't deduce script path for JavaScript object '{0}'", jsObject));
  181. }
  182. }
  183. if (string.IsNullOrEmpty(jsObject))
  184. {
  185. result = String.IsNullOrEmpty(scriptPath)
  186. ? ""
  187. : String.Format(@"<script type=""text/javascript"" src=""{0}""></script>", scriptPath);
  188. }
  189. else
  190. {
  191. if (jsObject == "DDRjQuery")
  192. {
  193. result = String.IsNullOrEmpty(scriptPath)
  194. ? @"<script type=""text/javascript"">DDRjQuery=window.DDRjQuery||jQuery;</script>"
  195. : String.Format(
  196. @"<script type=""text/javascript"">if (!window.DDRjQuery) {{if (window.jQuery && (jQuery.fn.jquery>=""1.3"")) DDRjQuery=jQuery; else document.write(unescape('%3Cscript src=""{0}"" type=""text/javascript""%3E%3C/script%3E'));}}</script><script type=""text/javascript"">if (!window.DDRjQuery) DDRjQuery=jQuery.noConflict(true);</script>",
  197. scriptPath);
  198. }
  199. else
  200. {
  201. result = String.IsNullOrEmpty(scriptPath)
  202. ? ""
  203. : String.Format(
  204. @"<script type=""text/javascript"">if (!({0})) document.write(unescape('%3Cscript src=""{1}"" type=""text/javascript""%3E%3C/script%3E'));</script>",
  205. GetObjectCheckScript(jsObject),
  206. scriptPath);
  207. }
  208. }
  209. return result;
  210. }
  211. private static string GetObjectCheckScript(string jsObject)
  212. {
  213. var objectParts = jsObject.Split('.');
  214. var objectToCheck = new StringBuilder("window");
  215. var objectsToCheck = new List<String>();
  216. foreach (var part in objectParts)
  217. {
  218. objectToCheck.AppendFormat(".{0}", part);
  219. objectsToCheck.Add(objectToCheck.ToString());
  220. }
  221. return String.Join(" && ", objectsToCheck.ToArray());
  222. }
  223. public TemplateDefinition Clone()
  224. {
  225. return (TemplateDefinition)MemberwiseClone();
  226. }
  227. public void Reset()
  228. {
  229. ClientOptions = new List<ClientOption>(DefaultClientOptions);
  230. TemplateArguments = new List<TemplateArgument>(DefaultTemplateArguments);
  231. }
  232. public void AddClientOptions(List<ClientOption> options, bool replace)
  233. {
  234. if (options != null)
  235. {
  236. foreach (var option in options)
  237. {
  238. var option1 = option;
  239. if (replace)
  240. {
  241. ClientOptions.RemoveAll(o => o.Name == option1.Name);
  242. }
  243. if (!ClientOptions.Exists(o => o.Name == option1.Name))
  244. {
  245. ClientOptions.Add(option);
  246. }
  247. }
  248. }
  249. }
  250. public void AddTemplateArguments(List<TemplateArgument> args, bool replace)
  251. {
  252. if (args != null)
  253. {
  254. foreach (var arg in args)
  255. {
  256. var arg1 = arg;
  257. if (replace)
  258. {
  259. TemplateArguments.RemoveAll(a => a.Name == arg1.Name);
  260. }
  261. if (!TemplateArguments.Exists(a => a.Name == arg1.Name))
  262. {
  263. TemplateArguments.Add(arg);
  264. }
  265. }
  266. }
  267. }
  268. internal void PreRender()
  269. {
  270. var page = DNNContext.Current.Page;
  271. var headControls = page.Header.Controls;
  272. var contextItems = HttpContext.Current.Items;
  273. foreach (var stylesheet in StyleSheets)
  274. {
  275. if (!contextItems.Contains(stylesheet))
  276. {
  277. var cssControl = new HtmlGenericControl("link");
  278. cssControl.Attributes.Add("rel", "stylesheet");
  279. cssControl.Attributes.Add("type", "text/css");
  280. cssControl.Attributes.Add("href", stylesheet);
  281. headControls.Add(cssControl);
  282. contextItems.Add(stylesheet, true);
  283. }
  284. }
  285. foreach (var scriptKey in ScriptKeys)
  286. {
  287. var clientScript = page.ClientScript;
  288. if (!clientScript.IsClientScriptBlockRegistered(typeof(TemplateDefinition), scriptKey))
  289. {
  290. clientScript.RegisterClientScriptBlock(typeof(TemplateDefinition), scriptKey, Scripts[scriptKey], false);
  291. }
  292. }
  293. var headContent = String.IsNullOrEmpty(TemplateHeadPath) ? "" : Utilities.CachedFileContent(TemplateHeadPath);
  294. var expandedHead = regexLinks.Replace(headContent, "$1" + DNNContext.Current.ActiveTab.SkinPath + "$3");
  295. page.Header.Controls.Add(new LiteralControl(expandedHead));
  296. }
  297. internal void Render(object source, HtmlTextWriter htmlWriter)
  298. {
  299. Processor.Render(source, htmlWriter, this);
  300. }
  301. }
  302. }