diff --git a/foreign dlls/RazorEngine.Core.dll b/foreign dlls/RazorEngine.Core.dll new file mode 100644 index 0000000000..9c2b080619 Binary files /dev/null and b/foreign dlls/RazorEngine.Core.dll differ diff --git a/foreign dlls/RazorEngine.Templates.dll b/foreign dlls/RazorEngine.Templates.dll new file mode 100644 index 0000000000..2bf91af8ad Binary files /dev/null and b/foreign dlls/RazorEngine.Templates.dll differ diff --git a/umbraco.MacroEngines.Juno/Razor/RazorCompiler.cs b/umbraco.MacroEngines.Juno/Razor/RazorCompiler.cs index b02472db4b..bd139a781e 100644 --- a/umbraco.MacroEngines.Juno/Razor/RazorCompiler.cs +++ b/umbraco.MacroEngines.Juno/Razor/RazorCompiler.cs @@ -1,6 +1,10 @@ using System.CodeDom; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; -namespace umbraco.MacroEngines.Razor { +namespace umbraco.MacroEngines.Razor +{ using System; using System.CodeDom.Compiler; using System.IO; @@ -13,9 +17,11 @@ namespace umbraco.MacroEngines.Razor { /// /// Compiles razor templates. /// - internal class RazorCompiler { + internal class RazorCompiler + { #region Fields private readonly IRazorProvider provider; + private Type templateBaseType; #endregion #region Constructor @@ -23,7 +29,8 @@ namespace umbraco.MacroEngines.Razor { /// Initialises a new instance of . /// /// The provider used to compile templates. - public RazorCompiler(IRazorProvider provider) { + public RazorCompiler(IRazorProvider provider) + { if (provider == null) throw new ArgumentNullException("provider"); @@ -38,7 +45,8 @@ namespace umbraco.MacroEngines.Razor { /// The class name of the dynamic type. /// The template to compile. /// [Optional] The mode type. - private CompilerResults Compile(string className, string template, Type modelType = null) { + private CompilerResults Compile(string className, string template, Type modelType = null) + { var languageService = provider.CreateLanguageService(); var codeDom = provider.CreateCodeDomProvider(); var host = new RazorEngineHost(languageService); @@ -56,9 +64,11 @@ namespace umbraco.MacroEngines.Razor { ? typeof(TemplateBaseDynamic) : typeof(TemplateBase<>).MakeGenericType(modelType)); + templateBaseType = baseType; generator.GeneratedClass.BaseTypes.Add(baseType); - using (var reader = new StreamReader(new MemoryStream(Encoding.ASCII.GetBytes(template)))) { + using (var reader = new StreamReader(new MemoryStream(Encoding.ASCII.GetBytes(template)))) + { parser.Parse(reader, generator); } @@ -66,25 +76,20 @@ namespace umbraco.MacroEngines.Razor { generator.GeneratedExecuteMethod.Statements.Insert(0, new CodeExpressionStatement(statement)); var builder = new StringBuilder(); - using (var writer = new StringWriter(builder)) { + using (var writer = new StringWriter(builder)) + { codeDom.GenerateCodeFromCompileUnit(generator.GeneratedCode, writer, new CodeGeneratorOptions()); } - var @params = new CompilerParameters(); -// @params.ReferencedAssemblies.Add("System"); -// @params.ReferencedAssemblies.Add("System.Web"); - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - if (!assembly.IsDynamic) - @params.ReferencedAssemblies.Add(assembly.Location); - } + var parameters = new CompilerParameters(); + AddReferences(parameters); - @params.GenerateInMemory = true; - @params.IncludeDebugInformation = false; - @params.GenerateExecutable = false; - @params.CompilerOptions = "/target:library /optimize"; + parameters.GenerateInMemory = true; + parameters.IncludeDebugInformation = false; + parameters.GenerateExecutable = false; + parameters.CompilerOptions = "/target:library /optimize"; - var result = codeDom.CompileAssemblyFromSource(@params, new[] { builder.ToString() }); + var result = codeDom.CompileAssemblyFromSource(parameters, new[] { builder.ToString() }); return result; } @@ -94,7 +99,8 @@ namespace umbraco.MacroEngines.Razor { /// The template to compile. /// [Optional] The model type. /// An instance of . - public ITemplate CreateTemplate(string template, Type modelType = null) { + public ITemplate CreateTemplate(string template, Type modelType = null) + { string className = Regex.Replace(Guid.NewGuid().ToString("N"), @"[^A-Za-z]*", ""); var result = Compile(className, template, modelType); @@ -107,5 +113,92 @@ namespace umbraco.MacroEngines.Razor { return instance; } #endregion + + /// + /// Adds any required references to the compiler parameters. + /// + /// The compiler parameters. + private void AddReferences(CompilerParameters parameters) + { + var list = new List(); + IEnumerable coreRefs = GetCoreReferences(); + foreach (string location in coreRefs) + { + list.Add(location.ToLowerInvariant()); + } + + IEnumerable baseRefs = GetBaseTypeReferencedAssemblies(); + foreach (string location in baseRefs) + { + list.Add(location.ToLowerInvariant()); + } + + foreach (string location in list) + System.Diagnostics.Debug.Print(location); + IEnumerable distinctList = list.Distinct(new AssemblyVersionComparer()); + parameters.ReferencedAssemblies.AddRange(distinctList.ToArray()); + } + + /// + /// Gets the locations of assemblies referenced by a custom base template type. + /// + /// An enumerable of reference assembly locations. + private IEnumerable GetBaseTypeReferencedAssemblies() + { + if (templateBaseType == null) + return new string[0]; + + return templateBaseType.Assembly + .GetReferencedAssemblies() + .Select(n => Assembly.ReflectionOnlyLoad(n.FullName).Location); + } + + + /// + /// Gets the locations of all core referenced assemblies. + /// + /// An enumerable of reference assembly locations. + private static IEnumerable GetCoreReferences() + { + var refs = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic).Select(a => a.Location); + + return refs.Concat(typeof(RazorCompiler) + .Assembly + .GetReferencedAssemblies().Select(n => Assembly.ReflectionOnlyLoad(n.FullName).Location)); + } + } + + public class AssemblyVersionComparer : IEqualityComparer + { + bool IEqualityComparer.Equals(string x, string y) + { + x = findAssemblyName(x); + y = findAssemblyName(y); + return (x.Contains(y) || y.Contains(x)); + } + + int IEqualityComparer.GetHashCode(string obj) + { + // 1) find the assembly name without version number and path (xxx.yyy.dll) + obj = findAssemblyName(obj); + // 2) send det som hashcode + if (Object.ReferenceEquals(obj, null)) + return 0; + return obj.GetHashCode(); + } + + private string findAssemblyName(string fullAssemblyPath) + { + + Regex r = new Regex(@"\\([^\\]*.dll)"); + Match m = r.Match(fullAssemblyPath); + if (m.Groups.Count > 0) + { + fullAssemblyPath = m.Groups[0].Value; + } + return fullAssemblyPath; + } + } + } \ No newline at end of file diff --git a/umbraco.MacroEngines.Juno/RazorEngine.cs b/umbraco.MacroEngines.Juno/RazorEngine.cs index cb735d7626..55e14a22cb 100644 --- a/umbraco.MacroEngines.Juno/RazorEngine.cs +++ b/umbraco.MacroEngines.Juno/RazorEngine.cs @@ -1,10 +1,15 @@ using System; using System.Collections.Generic; using System.IO; +using System.Security.Cryptography; +using System.Text; using System.Web; +using RazorEngine; +using RazorEngine.Templating; using umbraco.cms.businesslogic.macro; using umbraco.interfaces; using umbraco.IO; +using RE = RazorEngine; namespace umbraco.MacroEngines { @@ -40,25 +45,46 @@ namespace umbraco.MacroEngines string template = !String.IsNullOrEmpty(macro.ScriptCode) ? macro.ScriptCode : loadScript(IOHelper.MapPath(SystemDirectories.Python + "/" + macro.ScriptName)); try { - //TODO: Add caching support - // if (CacheTemplate) - // result = Razor.Parse(template, new DynamicNode(currentPage), this.ID + "_razorTemplate"); - // else - // { - result = Razor.Razor.Parse(template, new DynamicNode(currentPage)); + Razor.SetTemplateBaseType(typeof(UmbracoTemplateBase<>)); + result = Razor.Parse(template, new DynamicNode(currentPage), macro.CacheIdenitifier); + + } + catch (TemplateException ee) + { + string error = ee.ToString(); + if (ee.Errors.Count > 0) + { + error += "

Detailed errors:
    "; + foreach (var err in ee.Errors) + error += string.Format("
  • {0}
  • ", err.ToString()); + error += "

"; + } + result = string.Format( + "

Razor Macro Engine

An TemplateException occured while parsing the following code:

{0}

Your Razor template:

{1}

Cache key:

{2}

", + error, + HttpContext.Current.Server.HtmlEncode(template), + friendlyCacheKey(macro.CacheIdenitifier)); } - // } catch (Exception ee) { result = string.Format( - "

Razor Macro Engine

An error occured while rendering the following code:

{0}

{1}
", + "

Razor Macro Engine

An unknown error occured while rendering the following code:

{0}

Your Razor template:

{1}

Cache key:

{2}

", ee.ToString(), - HttpContext.Current.Server.HtmlEncode(template)); + HttpContext.Current.Server.HtmlEncode(template), + friendlyCacheKey(macro.CacheIdenitifier)); } return result; } + private string friendlyCacheKey(string cacheKey) + { + if (!String.IsNullOrEmpty(cacheKey)) + return cacheKey; + else + return "No caching defined"; + } + private string loadScript(string scriptName) { if (File.Exists(scriptName)) @@ -68,5 +94,28 @@ namespace umbraco.MacroEngines return String.Empty; } + + } + + public abstract class UmbracoTemplateBase : TemplateBase + { + private object m_model; + + public override T Model + { + get + { + return (T)m_model; + } + set + { + m_model = value; + } + } + + public string ToUpperCase(string name) + { + return name.ToUpper(); + } } } diff --git a/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj b/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj index 55c7024c08..2de07b2d3b 100644 --- a/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj +++ b/umbraco.MacroEngines.Juno/umbraco.MacroEngines.csproj @@ -42,17 +42,22 @@ ..\foreign dlls\DLR 4.0\Microsoft.Scripting.dll + + ..\foreign dlls\RazorEngine.Core.dll + + + ..\foreign dlls\RazorEngine.Templates.dll + + False ..\foreign dlls\System.Web.Razor.dll - - @@ -60,14 +65,6 @@ - - - - - - - - diff --git a/umbraco/cms/businesslogic/macro/Macro.cs b/umbraco/cms/businesslogic/macro/Macro.cs index 44031b1f96..f93d0039b6 100644 --- a/umbraco/cms/businesslogic/macro/Macro.cs +++ b/umbraco/cms/businesslogic/macro/Macro.cs @@ -1,5 +1,7 @@ using System; using System.Data; +using System.Security.Cryptography; +using System.Text; using System.Xml; using System.Runtime.CompilerServices; @@ -503,6 +505,49 @@ namespace umbraco.cms.businesslogic.macro } } + public static MacroTypes FindMacroType(string xslt, string scriptFile, string scriptType, string scriptAssembly) + { + if (!string.IsNullOrEmpty(xslt)) + return MacroTypes.XSLT; + else + { + if (!string.IsNullOrEmpty(scriptFile)) + return MacroTypes.Script; + else + { + if (!string.IsNullOrEmpty(scriptType) && scriptType.ToLower().IndexOf(".ascx") > -1) + { + return MacroTypes.UserControl; + } + else if (!string.IsNullOrEmpty(scriptType) && !string.IsNullOrEmpty(scriptAssembly)) + return MacroTypes.CustomControl; + } + } + + return MacroTypes.Unknown; + } + + public static string GenerateCacheKeyFromCode(string input) + { + if (String.IsNullOrEmpty(input)) + throw new ArgumentNullException("input", "An MD5 hash cannot be generated when 'input' parameter is null!"); + + // step 1, calculate MD5 hash from input + MD5 md5 = System.Security.Cryptography.MD5.Create(); + byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input); + byte[] hash = md5.ComputeHash(inputBytes); + + // step 2, convert byte array to hex string + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < hash.Length; i++) + { + sb.Append(hash[i].ToString("X2")); + } + return sb.ToString(); + } + + + //Macro events //Delegates diff --git a/umbraco/cms/businesslogic/macro/MacroModel.cs b/umbraco/cms/businesslogic/macro/MacroModel.cs index 5a5d3cb47e..9f45072a7c 100644 --- a/umbraco/cms/businesslogic/macro/MacroModel.cs +++ b/umbraco/cms/businesslogic/macro/MacroModel.cs @@ -12,16 +12,20 @@ namespace umbraco.cms.businesslogic.macro { public string Name { get; set; } public string Alias { get; set; } + public string MacroControlIdentifier { get; set; } + public MacroTypes MacroType { get; set; } public string TypeAssembly { get; set; } public string TypeName { get; set; } public string Xslt { get; set; } public string ScriptName { get; set; } public string ScriptCode { get; set; } + public string ScriptLanguage { get; set; } public int CacheDuration { get; set; } public bool CacheByPage { get; set; } public bool CacheByMember { get; set; } + public string CacheIdenitifier { get; set; } public List Properties { get; set; } @@ -43,6 +47,8 @@ namespace umbraco.cms.businesslogic.macro CacheByMember = cacheByMember; Properties = new List(); + + MacroType = Macro.FindMacroType(Xslt, ScriptName, TypeName, TypeAssembly); } } @@ -63,4 +69,16 @@ namespace umbraco.cms.businesslogic.macro Value = value; } } + + public enum MacroTypes + { + XSLT = 1, + CustomControl = 2, + UserControl = 3, + Unknown = 4, + Python = 5, + Script = 6 + } + + } diff --git a/umbraco/presentation/config/Dashboard.config b/umbraco/presentation/config/Dashboard.config index fcb784a54e..5d59760924 100644 --- a/umbraco/presentation/config/Dashboard.config +++ b/umbraco/presentation/config/Dashboard.config @@ -54,7 +54,7 @@ /usercontrols/propertyTest.ascx - + /umbraco/dashboard/startupdashboardintro.ascx @@ -88,4 +88,24 @@ +
+ + content + + + /usercontrols/blog/CommentModeration.ascx + +
+
+ + default + content + + + /usercontrols/dashboards/ContactForm_logs.ascx + + + /usercontrols/dashboards/EmailAFriendForm_logs.ascx + +
\ No newline at end of file diff --git a/umbraco/presentation/config/UrlRewriting.config b/umbraco/presentation/config/UrlRewriting.config index 58fb55ea48..020f541879 100644 --- a/umbraco/presentation/config/UrlRewriting.config +++ b/umbraco/presentation/config/UrlRewriting.config @@ -29,5 +29,6 @@ Any bugs or problems with the rewriter, contact Anders/Duckie --> + \ No newline at end of file diff --git a/umbraco/presentation/config/metablogConfig.config b/umbraco/presentation/config/metablogConfig.config index 06fafc8306..585ebd0bf5 100644 --- a/umbraco/presentation/config/metablogConfig.config +++ b/umbraco/presentation/config/metablogConfig.config @@ -5,11 +5,12 @@ 0 1080 False - FAQItem + umbBlog - answer + + diff --git a/umbraco/presentation/config/restExtensions.config b/umbraco/presentation/config/restExtensions.config index 991dde0bc7..88aa956085 100644 --- a/umbraco/presentation/config/restExtensions.config +++ b/umbraco/presentation/config/restExtensions.config @@ -10,4 +10,8 @@ --> + + + + \ No newline at end of file diff --git a/umbraco/presentation/config/xsltExtensions.config b/umbraco/presentation/config/xsltExtensions.config index 44e4344593..e83c1dea04 100644 --- a/umbraco/presentation/config/xsltExtensions.config +++ b/umbraco/presentation/config/xsltExtensions.config @@ -2,5 +2,6 @@ - + + \ No newline at end of file diff --git a/umbraco/presentation/macro.cs b/umbraco/presentation/macro.cs index 4b1fc37c29..7211c3633d 100644 --- a/umbraco/presentation/macro.cs +++ b/umbraco/presentation/macro.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.IO; using System.Net; using System.Reflection; +using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; @@ -68,16 +69,6 @@ namespace umbraco #region public properties - public enum eMacroType - { - XSLT = 1, - CustomControl = 2, - UserControl = 3, - Unknown = 4, - Python = 5, - Script = 6 - } - public int MacroID { set { macroID = value; } @@ -233,24 +224,7 @@ namespace umbraco macroCache.Insert(macroCacheIdentifier + id, this); } - if (!string.IsNullOrEmpty(XsltFile)) - macroType = (int)eMacroType.XSLT; - else - { - if (!string.IsNullOrEmpty(ScriptFile)) - macroType = (int)eMacroType.Script; - else - { - if (!string.IsNullOrEmpty(ScriptType) && ScriptType.ToLower().IndexOf(".ascx") > -1) - { - macroType = (int)eMacroType.UserControl; - } - else if (!string.IsNullOrEmpty(ScriptType) && !string.IsNullOrEmpty(ScriptAssembly)) - macroType = (int)eMacroType.CustomControl; - } - } - if (macroType.ToString() == string.Empty) - macroType = (int)eMacroType.Unknown; + macroType = (int)Macro.FindMacroType(XsltFile, ScriptFile, ScriptType, ScriptAssembly); } public override string ToString() @@ -346,9 +320,11 @@ namespace umbraco return false; } - private string getCacheGuid(Hashtable attributes, Hashtable pageElements, int pageId) + private string getCacheGuid(MacroModel model, Hashtable pageElements, int pageId) { - string tempGuid = string.Empty; + string tempGuid = !String.IsNullOrEmpty(model.ScriptCode) + ? Macro.GenerateCacheKeyFromCode(model.ScriptCode) + "-" + : model.Alias + "-"; if (CacheByPage) { @@ -362,11 +338,9 @@ namespace umbraco else tempGuid += "m"; } - - IDictionaryEnumerator id = attributes.GetEnumerator(); - while (id.MoveNext()) + foreach (MacroPropertyModel prop in model.Properties) { - string attValue = helper.FindAttribute(pageElements, attributes, id.Key.ToString()); + string attValue = prop.Value; if (attValue.Length > 255) tempGuid += attValue.Remove(255, attValue.Length - 255) + "-"; else @@ -376,38 +350,45 @@ namespace umbraco } public Control renderMacro(Hashtable attributes, Hashtable pageElements, int pageId) + { + MacroModel m = ConvertToMacroModel(attributes); + return renderMacro(m, pageElements, pageId); + } + + public Control renderMacro(MacroModel model, Hashtable pageElements, int pageId) { HttpContext.Current.Trace.Write("renderMacro", string.Format("Rendering started (macro: {0}, type: {1}, cacheRate: {2})", - Name, MacroType, RefreshRate)); + Name, MacroType, model.CacheDuration)); StateHelper.SetContextValue(macrosAddedKey, StateHelper.GetContextValue(macrosAddedKey) + 1); String macroHtml = null; Control macroControl = null; - string macroGuid = getCacheGuid(attributes, pageElements, pageId); + model.CacheIdenitifier = getCacheGuid(model, pageElements, pageId); - if (RefreshRate > 0) + if (model.CacheDuration > 0) { - macroHtml = macroCache["macroHtml_" + macroGuid] as String; + macroHtml = macroCache["macroHtml_" + model.CacheIdenitifier] as String; if (!String.IsNullOrEmpty(macroHtml)) { - macroHtml = macroCache["macroHtml_" + macroGuid] as String; - HttpContext.Current.Trace.Write("renderMacro", "Content loaded from cache ('" + macroGuid + "')..."); + macroHtml = macroCache["macroHtml_" + model.CacheIdenitifier] as String; + HttpContext.Current.Trace.Write("renderMacro", "Content loaded from cache ('" + model.CacheIdenitifier + "')..."); } } if (String.IsNullOrEmpty(macroHtml)) { - switch (MacroType) + int macroType = model.MacroType != MacroTypes.Unknown ? (int)model.MacroType : MacroType; + switch (macroType) { - case (int)eMacroType.UserControl: + case (int)MacroTypes.UserControl: try { HttpContext.Current.Trace.Write("umbracoMacro", "Usercontrol added (" + scriptType + ")"); - macroControl = loadUserControl(ScriptType, attributes, pageElements); + macroControl = loadUserControl(ScriptType, model, pageElements); break; } catch (Exception e) @@ -417,12 +398,12 @@ namespace umbraco macroControl = new LiteralControl("Error loading userControl '" + scriptType + "'"); break; } - case (int)eMacroType.CustomControl: + case (int)MacroTypes.CustomControl: try { HttpContext.Current.Trace.Write("umbracoMacro", "Custom control added (" + scriptType + ")"); HttpContext.Current.Trace.Write("umbracoMacro", "ScriptAssembly (" + scriptAssembly + ")"); - macroControl = loadControl(scriptAssembly, ScriptType, attributes, pageElements); + macroControl = loadControl(scriptAssembly, ScriptType, model, pageElements); break; } catch (Exception e) @@ -436,15 +417,14 @@ namespace umbraco scriptType + "'"); break; } - case (int)eMacroType.XSLT: - macroControl = loadMacroXSLT(this, attributes, pageElements); + case (int)MacroTypes.XSLT: + macroControl = loadMacroXSLT(this, model, pageElements); break; - case (int)eMacroType.Script: + case (int)MacroTypes.Script: try { HttpContext.Current.Trace.Write("umbracoMacro", "MacroEngine script added (" + ScriptFile + ")"); - MacroModel model = ConvertToMacroModel(attributes); macroControl = loadMacroDLR(model); break; } @@ -482,10 +462,10 @@ namespace umbraco } // Add result to cache - if (RefreshRate > 0) + if (model.CacheDuration > 0) { // do not add to cache if there's no member and it should cache by personalization - if (!CacheByPersonalization || (CacheByPersonalization && Member.GetCurrentMember() != null)) + if (!model.CacheByMember || (model.CacheByMember && Member.GetCurrentMember() != null)) { if (macroControl != null) { @@ -494,10 +474,10 @@ namespace umbraco var hw = new HtmlTextWriter(sw); macroControl.RenderControl(hw); - macroCache.Insert("macroHtml_" + macroGuid, + macroCache.Insert("macroHtml_" + model.CacheIdenitifier, sw.ToString(), null, - DateTime.Now.AddSeconds(RefreshRate), + DateTime.Now.AddSeconds(model.CacheDuration), TimeSpan.Zero, CacheItemPriority.Low, null); @@ -599,13 +579,10 @@ namespace umbraco return retval; } - public Control loadMacroXSLT(macro macro, Hashtable attributes, Hashtable pageElements) + public Control loadMacroXSLT(macro macro, MacroModel model, Hashtable pageElements) { if (XsltFile.Trim() != string.Empty) { - //get attributes in lowercase... - attributes = keysToLowerCase(keysToLowerCase(attributes)); - // Get main XML XmlDocument umbracoXML = content.Instance.XmlContent; @@ -615,20 +592,19 @@ namespace umbraco foreach (DictionaryEntry macroDef in macro.properties) { - try + var prop = model.Properties.Find(m => m.Key == (string)macroDef.Key); + string propValue = prop != null + ? helper.parseAttribute(pageElements, prop.Value) + : helper.parseAttribute(pageElements, ""); + if (!String.IsNullOrEmpty(propValue)) { - if (helper.FindAttribute(pageElements, attributes, macroDef.Key.ToString()) != string.Empty) + if (propValue != string.Empty) addMacroXmlNode(umbracoXML, macroXML, macroDef.Key.ToString(), macroDef.Value.ToString(), - helper.FindAttribute(pageElements, attributes, macroDef.Key.ToString())); + propValue); else addMacroXmlNode(umbracoXML, macroXML, macroDef.Key.ToString(), macroDef.Value.ToString(), string.Empty); } - catch (Exception e) - { - HttpContext.Current.Trace.Warn("umbracoMacro", "Could not write XML node (" + macroDef.Key + ")", - e); - } } if (HttpContext.Current.Request.QueryString["umbDebug"] != null && GlobalSettings.DebugMode) @@ -1072,79 +1048,25 @@ namespace umbraco return string.Empty; } - /// - /// Executes a python script. - /// - /// The instance of the macro (this). No idea why passed. - /// Relayed attributes to determine the values of the passed properties. - /// The current page. - /// Returns a LiteralControl stuffed with the StandardOutput of the script execution. - public Control loadMacroPython(macro macro, Hashtable attributes, Hashtable pageElements) - { - var ret = new LiteralControl(); - try - { - // Adding some global accessible variables to the enviroment. - // Currently no cleanup after execution is done. - var args = new Hashtable(); - HttpContext.Current.Session.Add("pageElements", pageElements); - HttpContext.Current.Session.Add("macro", this); - HttpContext.Current.Session.Add("args", args); - - foreach (DictionaryEntry macroDef in macro.properties) - { - try - { - args.Add(macroDef.Key.ToString(), - helper.FindAttribute(pageElements, attributes, macroDef.Key.ToString())); - } - catch (Exception e) - { - HttpContext.Current.Trace.Warn("umbracoMacro", - "Could not add global variable (" + macroDef.Key + - ") to python enviroment", e); - } - } - - if (string.IsNullOrEmpty(macro.ScriptFile)) - { - ret.Text = string.Empty; - } - else - { - // Execute the script and set the text of our LiteralControl with the returned - // result of our script. - string path = IOHelper.MapPath(SystemDirectories.Python + "/" + macro.scriptFile); - object res = python.executeFile(path); - ret.Text = res.ToString(); - } - } - catch (Exception ex) - { - // Let's collect as much info we can get and display it glaring red - ret.Text = "
"; - Exception ie = ex; - while (ie != null) - { - ret.Text += "
" + ie.Message + "
"; - ret.Text += ie.StackTrace + "
"; - - ie = ie.InnerException; - } - ret.Text += "
"; - } - return ret; - } - - public Control loadMacroDLR(MacroModel macro) { + TraceInfo("umbracoMacro", "Loading IMacroEngine script"); var ret = new LiteralControl(); + if (macro.ScriptCode != String.Empty) + { + IMacroEngine engine = MacroEngineFactory.GetByExtension(macro.ScriptLanguage); + ret.Text = engine.Execute( + macro, + Node.GetCurrent()); - string path = IOHelper.MapPath(SystemDirectories.Python + "/" + macro.ScriptName); - IMacroEngine engine = MacroEngineFactory.GetByFilename(path); - ret.Text = engine.Execute(macro, Node.GetCurrent()); - + } + else + { + string path = IOHelper.MapPath(SystemDirectories.Python + "/" + macro.ScriptName); + IMacroEngine engine = MacroEngineFactory.GetByFilename(path); + ret.Text = engine.Execute(macro, Node.GetCurrent()); + } + TraceInfo("umbracoMacro", "Loading IMacroEngine script [done]"); return ret; } @@ -1155,9 +1077,9 @@ namespace umbraco /// Name of the control /// /// - public Control loadControl(string fileName, string controlName, Hashtable attributes) + public Control loadControl(string fileName, string controlName, MacroModel model) { - return loadControl(fileName, controlName, attributes, null); + return loadControl(fileName, controlName, model, null); } /// @@ -1168,7 +1090,7 @@ namespace umbraco /// /// /// - public Control loadControl(string fileName, string controlName, Hashtable attributes, Hashtable pageElements) + public Control loadControl(string fileName, string controlName, MacroModel model, Hashtable pageElements) { Type type; Assembly asm; @@ -1213,14 +1135,16 @@ namespace umbraco { if (HttpContext.Current != null) HttpContext.Current.Trace.Warn("macro", - string.Format("control property '{0} ({1})' didn't work", - propertyAlias, - helper.FindAttribute(attributes, propertyAlias))); + string.Format("control property '{0}' doesn't exist or aren't accessible (public)", + propertyAlias)); continue; } - object propValue = helper.FindAttribute(pageElements, attributes, propertyAlias); + MacroPropertyModel propModel = model.Properties.Find(m => m.Key == propertyAlias); + object propValue = propModel != null + ? helper.parseAttribute(pageElements, propModel.Value) + : helper.parseAttribute(pageElements, ""); // Special case for types of webControls.unit if (prop.PropertyType == typeof(Unit)) propValue = Unit.Parse(propValue.ToString()); @@ -1255,13 +1179,6 @@ namespace umbraco } prop.SetValue(control, Convert.ChangeType(propValue, prop.PropertyType), null); - - if (HttpContext.Current != null) - HttpContext.Current.Trace.Write("macro", - string.Format("control property '{0} ({1})' worked", - propertyAlias, - helper.FindAttribute(pageElements, attributes, - propertyAlias))); } return control; } @@ -1273,10 +1190,10 @@ namespace umbraco /// The attributes. /// The page elements. /// - public Control loadUserControl(string fileName, Hashtable attributes, Hashtable pageElements) + public Control loadUserControl(string fileName, MacroModel model, Hashtable pageElements) { Debug.Assert(!string.IsNullOrEmpty(fileName), "fileName cannot be empty"); - Debug.Assert(attributes != null, "attributes cannot be null"); + Debug.Assert(model.Properties != null, "attributes cannot be null"); Debug.Assert(pageElements != null, "pageElements cannot be null"); try { @@ -1291,8 +1208,8 @@ namespace umbraco if (slashIndex < 0) slashIndex = 0; - if (attributes["controlID"] != null) - oControl.ID = attributes["controlID"].ToString(); + if (!String.IsNullOrEmpty(model.MacroControlIdentifier)) + oControl.ID = model.MacroControlIdentifier; else oControl.ID = string.Format("{0}_{1}", fileName.Substring(slashIndex, fileName.IndexOf(".ascx") - slashIndex), @@ -1318,10 +1235,12 @@ namespace umbraco continue; } - object propValue = - helper.FindAttribute(pageElements, attributes, propertyAlias).Replace("&", "&").Replace( - """, "\"").Replace("<", "<").Replace(">", ">"); - if (string.IsNullOrEmpty(propValue as string)) + MacroPropertyModel propModel = model.Properties.Find(m => m.Key == propertyAlias); + object propValue = propModel != null + ? helper.parseAttribute(pageElements, propModel.Value) + : helper.parseAttribute(pageElements, ""); + + if (propValue != null) continue; // Special case for types of webControls.unit @@ -1592,6 +1511,7 @@ namespace umbraco xslt = xslt.Replace("{1}", namespaceList.ToString()); return xslt; } + } public class MacroCacheContent diff --git a/umbraco/presentation/umbraco/templateControls/Macro.cs b/umbraco/presentation/umbraco/templateControls/Macro.cs index 52bdff446c..107bb3ac61 100644 --- a/umbraco/presentation/umbraco/templateControls/Macro.cs +++ b/umbraco/presentation/umbraco/templateControls/Macro.cs @@ -102,27 +102,48 @@ namespace umbraco.presentation.templateControls if (!MacroAttributes.ContainsKey("macroalias") && !MacroAttributes.ContainsKey("macroAlias")) MacroAttributes.Add("macroalias", Alias); + // set pageId to int.MinValue if no pageID was found, + // e.g. if the macro was rendered on a custom (non-Umbraco) page + int pageId = Context.Items["pageID"] == null ? int.MinValue : int.Parse(Context.Items["pageID"].ToString()); + if (!String.IsNullOrEmpty(Language) && Text != "") { - //TODO: FOR JUNO RC: Move this into the Macro object to ensure caching etc macro m = new macro(); + MacroModel model = m.ConvertToMacroModel(MacroAttributes); model.ScriptCode = Text; - IMacroEngine engine = MacroEngineFactory.GetByExtension(Language); + model.ScriptLanguage = Language; + model.MacroType = MacroTypes.Script; + if (!String.IsNullOrEmpty(Attributes["Cache"])) + { + int cacheDuration = 0; + if (int.TryParse(Attributes["Cache"], out cacheDuration)) + { + model.CacheDuration = cacheDuration; + } + else + { + System.Web.HttpContext.Current.Trace.Warn("Template", + "Cache attribute is in incorect format (should be an integer)."); + } + } + Control c = m.renderMacro(model, (Hashtable)Context.Items["pageElements"], pageId); + if (c != null) + Controls.Add(c); + else + System.Web.HttpContext.Current.Trace.Warn("Template", "Result of inline macro scripting is null"); + + /*IMacroEngine engine = MacroEngineFactory.GetByExtension(Language); string result = engine.Execute( model, Node.GetCurrent()); - Controls.Add(new LiteralControl(result)); + Controls.Add(new LiteralControl(result));*/ } else { macro tempMacro = null; tempMacro = macro.ReturnFromAlias(Alias); - // set pageId to int.MinValue if no pageID was found, - // e.g. if the macro was rendered on a custom (non-Umbraco) page - int pageId = Context.Items["pageID"] == null ? int.MinValue : int.Parse(Context.Items["pageID"].ToString()); - if (tempMacro != null) {