diff --git a/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs new file mode 100644 index 0000000000..8f3866472a --- /dev/null +++ b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Umbraco.Core.IO; + +namespace umbraco.cms.businesslogic.template +{ + internal class MasterpageHelper + { + internal static readonly string DefaultMasterTemplate = SystemDirectories.Umbraco + "/masterpages/default.master"; + internal static string CreateMasterpageFile(Template t, bool overWrite = false) + { + string masterpageContent = ""; + + if (!File.Exists(t.MasterPageFile) || overWrite) + masterpageContent = saveTemplateToFile(t, t.Alias); + else + { + System.IO.TextReader tr = new StreamReader(t.MasterPageFile); + masterpageContent = tr.ReadToEnd(); + tr.Close(); + } + + return masterpageContent; + } + + internal static string GetMasterpageFile(Template t) + { + string masterpageContent = ""; + if (File.Exists(t.MasterPageFile)){ + System.IO.TextReader tr = new StreamReader(t.MasterPageFile); + masterpageContent = tr.ReadToEnd(); + tr.Close(); + } + + return masterpageContent; + } + + internal static string UpdateMasterpageFile(Template t, string currentAlias) + { + return saveTemplateToFile(t, currentAlias); + } + + internal static string saveTemplateToFile(Template template, string currentAlias) + { + var masterPageContent = template.Design; + if (!isMasterPageSyntax(masterPageContent)) + masterPageContent = ConvertToMasterPageSyntax(template); + + // Add header to master page if it doesn't exist + if (!masterPageContent.TrimStart().StartsWith("<%@")) + { + masterPageContent = getMasterPageHeader(template) + "\n" + masterPageContent; + } + else + { + // verify that the masterpage attribute is the same as the masterpage + string masterHeader = + masterPageContent.Substring(0, masterPageContent.IndexOf("%>") + 2).Trim( + Environment.NewLine.ToCharArray()); + + // find the masterpagefile attribute + MatchCollection m = Regex.Matches(masterHeader, "(?\\S*)=\"(?[^\"]*)\"", + RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); + + foreach (Match attributeSet in m) + { + if (attributeSet.Groups["attributeName"].Value.ToLower() == "masterpagefile") + { + // validate the masterpagefile + string currentMasterPageFile = attributeSet.Groups["attributeValue"].Value; + string currentMasterTemplateFile = parentTemplatePath(template); + + if (currentMasterPageFile != currentMasterTemplateFile) + { + masterPageContent = + masterPageContent.Replace( + attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterPageFile + "\"", + attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterTemplateFile + + "\""); + + } + } + } + + } + + //we have a Old Alias if the alias and therefor the masterpage file name has changed... + //so before we save the new masterfile, we'll clear the old one, so we don't up with + //Unused masterpage files + if (!string.IsNullOrEmpty(currentAlias) && currentAlias != template.Alias) + { + + //Ensure that child templates have the right master masterpage file name + if (template.HasChildren) + { + //store children array here because iterating over an Array property object is very inneficient. + var c = template.Children; + foreach (CMSNode cmn in c) + UpdateMasterpageFile(new Template(cmn.Id), null); + } + + //then kill the old file.. + string _oldFile = IOHelper.MapPath(SystemDirectories.Masterpages + "/" + currentAlias.Replace(" ", "") + ".master"); + if (System.IO.File.Exists(_oldFile)) + System.IO.File.Delete(_oldFile); + } + + // save the file in UTF-8 + System.IO.File.WriteAllText(template.MasterPageFile, masterPageContent, System.Text.Encoding.UTF8); + + return masterPageContent; + } + + internal static string ConvertToMasterPageSyntax(Template template) + { + string masterPageContent = GetMasterContentElement(template) + "\n"; + + masterPageContent += template.Design; + + // Parse the design for getitems + masterPageContent = EnsureMasterPageSyntax(template.Alias, masterPageContent); + + // append ending asp:content element + masterPageContent += "\n" + Environment.NewLine; + + return masterPageContent; + } + + private static bool isMasterPageSyntax(string code) + { + return code.Contains("<%@ Master") || code.Contains("", parentTemplatePath(template)) + Environment.NewLine; + } + + private static string parentTemplatePath(Template template) + { + var masterTemplate = DefaultMasterTemplate; + if (template.MasterTemplate != 0) + masterTemplate = SystemDirectories.Masterpages + "/" + new Template(template.MasterTemplate).Alias.Replace(" ", "") + ".master"; + + return masterTemplate; + } + + private static string GetMasterContentElement(Template template) + { + if (template.MasterTemplate != 0) + { + string masterAlias = new Template(template.MasterTemplate).Alias.Replace(" ", ""); + return + String.Format("", + template.Alias.Replace(" ", ""), masterAlias); + } + else + return + String.Format("", + template.Alias.Replace(" ", "")); + + } + + internal static string EnsureMasterPageSyntax(string templateAlias, string masterPageContent) + { + replaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", true); + replaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", false); + + // Parse the design for macros + replaceElement(ref masterPageContent, "?UMBRACO_MACRO", "umbraco:Macro", true); + replaceElement(ref masterPageContent, "?UMBRACO_MACRO", "umbraco:Macro", false); + + // Parse the design for load childs + masterPageContent = masterPageContent.Replace("", createDefaultPlaceHolder(templateAlias)) + .Replace("", createDefaultPlaceHolder(templateAlias)); + // Parse the design for aspnet forms + getAspNetMasterPageForm(ref masterPageContent, templateAlias); + masterPageContent = masterPageContent.Replace("", ""); + // Parse the design for aspnet heads + masterPageContent = masterPageContent.Replace("", String.Format("", templateAlias.Replace(" ", ""))); + masterPageContent = masterPageContent.Replace("", ""); + return masterPageContent; + } + + + private static void getAspNetMasterPageForm(ref string design, string templateAlias) + { + Match formElement = Regex.Match(design, getElementRegExp("?ASPNET_FORM", false), RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); + + if (formElement != null && formElement.Value != "") + { + string formReplace = String.Format("
", templateAlias.Replace(" ", "")); + if (formElement.Groups.Count == 0) + { + formReplace += ""; + } + design = design.Replace(formElement.Value, formReplace); + } + } + + private static string createDefaultPlaceHolder(string templateAlias) + { + return String.Format("", templateAlias.Replace(" ", "")); + } + + private static void replaceElement(ref string design, string elementName, string newElementName, bool checkForQuotes) + { + MatchCollection m = + Regex.Matches(design, getElementRegExp(elementName, checkForQuotes), + RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); + + foreach (Match match in m) + { + GroupCollection groups = match.Groups; + + // generate new element (compensate for a closing trail on single elements ("/")) + string elementAttributes = groups[1].Value; + // test for macro alias + if (elementName == "?UMBRACO_MACRO") + { + Hashtable tags = helpers.xhtml.ReturnAttributes(match.Value); + if (tags["macroAlias"] != null) + elementAttributes = String.Format(" Alias=\"{0}\"", tags["macroAlias"].ToString()) + elementAttributes; + else if (tags["macroalias"] != null) + elementAttributes = String.Format(" Alias=\"{0}\"", tags["macroalias"].ToString()) + elementAttributes; + } + string newElement = "<" + newElementName + " runat=\"server\" " + elementAttributes.Trim() + ">"; + if (elementAttributes.EndsWith("/")) + { + elementAttributes = elementAttributes.Substring(0, elementAttributes.Length - 1); + } + else if (groups[0].Value.StartsWith(""; + + if (checkForQuotes) + { + // if it's inside quotes, we'll change element attribute quotes to single quotes + newElement = newElement.Replace("\"", "'"); + newElement = String.Format("\"{0}\"", newElement); + } + design = design.Replace(match.Value, newElement); + } + } + + private static string getElementRegExp(string elementName, bool checkForQuotes) + { + if (checkForQuotes) + return String.Format("\"<[^>\\s]*\\b{0}(\\b[^>]*)>\"", elementName); + else + return String.Format("<[^>\\s]*\\b{0}(\\b[^>]*)>", elementName); + + } + + } +} diff --git a/src/umbraco.cms/businesslogic/template/Template.cs b/src/umbraco.cms/businesslogic/template/Template.cs index a87488768c..f8a00f842e 100644 --- a/src/umbraco.cms/businesslogic/template/Template.cs +++ b/src/umbraco.cms/businesslogic/template/Template.cs @@ -132,12 +132,12 @@ namespace umbraco.cms.businesslogic.template _mastertemplate = dr.IsNull("master") ? 0 : dr.GetInt("master"); } dr.Close(); + + if (UmbracoSettings.EnableMvcSupport && Template.HasView(this)) + _design = ViewHelper.GetViewFile(this); + else + _design = MasterpageHelper.GetMasterpageFile(this); - // test for masterpages - if (UmbracoSettings.UseAspNetMasterPages) - { - _design = getMasterPageContent(); - } } private bool isMasterPageSyntax(string code) @@ -145,18 +145,6 @@ namespace umbraco.cms.businesslogic.template return code.Contains("<%@ Master") || code.Contains("") + 3).Trim(Environment.NewLine.ToCharArray()); - if (UmbracoSettings.UseAspNetMasterPages && isMasterPageSyntax(_design)) - { - SaveMasterPageFile(_design); - SqlHelper.ExecuteNonQuery("Update cmsTemplate set design = @design where NodeId = @id", - SqlHelper.CreateParameter("@design", value), - SqlHelper.CreateParameter("@id", Id)); + //we only switch to MVC View editing if the template has a view file, and MVC editing is enabled + if (UmbracoSettings.EnableMvcSupport && !isMasterPageSyntax(_design)) + _design = ViewHelper.UpdateViewFile(this); + else if (UmbracoSettings.UseAspNetMasterPages) + _design = MasterpageHelper.UpdateMasterpageFile(this, _oldAlias); + - } - else - SqlHelper.ExecuteNonQuery("Update cmsTemplate set design = @design where NodeId = @id", - SqlHelper.CreateParameter("@design", value), + SqlHelper.ExecuteNonQuery("Update cmsTemplate set design = @design where NodeId = @id", + SqlHelper.CreateParameter("@design", _design), SqlHelper.CreateParameter("@id", Id)); } } @@ -331,11 +318,17 @@ namespace umbraco.cms.businesslogic.template public static Template MakeNew(string Name, BusinessLogic.User u, Template master) { - Template t = MakeNew(Name, u); t.MasterTemplate = master.Id; - t.Design = ""; + if (UmbracoSettings.EnableMvcSupport) + ViewHelper.CreateViewFile(t, true); + else + MasterpageHelper.CreateMasterpageFile(t, true); + + + + /* if (UmbracoSettings.UseAspNetMasterPages) { string design = t.getMasterPageHeader() + "\n"; @@ -346,7 +339,7 @@ namespace umbraco.cms.businesslogic.template } t.Design = design; - } + }*/ t.Save(); return t; @@ -367,6 +360,8 @@ namespace umbraco.cms.businesslogic.template if (name.Length > 100) name = name.Substring(0, 95) + "..."; + + SqlHelper.ExecuteNonQuery("INSERT INTO cmsTemplate (NodeId, Alias, design, master) VALUES (@nodeId, @alias, @design, @master)", SqlHelper.CreateParameter("@nodeId", n.Id), @@ -378,6 +373,12 @@ namespace umbraco.cms.businesslogic.template NewEventArgs e = new NewEventArgs(); t.OnNew(e); + if (UmbracoSettings.EnableMvcSupport) + t._design = ViewHelper.CreateViewFile(t); + else + t._design = MasterpageHelper.CreateMasterpageFile(t); + + return t; } @@ -504,13 +505,17 @@ namespace umbraco.cms.businesslogic.template if (System.IO.File.Exists(MasterPageFile)) System.IO.File.Delete(MasterPageFile); + if (System.IO.File.Exists(Umbraco.Core.IO.IOHelper.MapPath(ViewHelper.ViewPath(this)))) + System.IO.File.Delete(Umbraco.Core.IO.IOHelper.MapPath(ViewHelper.ViewPath(this))); + FireAfterDelete(e); } } - public void SaveAsMasterPage() + [Obsolete("This method, doesnt actually do anything, as the file is created when the design is set", false)] + public void _SaveAsMasterPage() { - SaveMasterPageFile(ConvertToMasterPageSyntax(Design)); + //SaveMasterPageFile(ConvertToMasterPageSyntax(Design)); } public string GetMasterContentElement(int masterTemplateId) @@ -526,7 +531,6 @@ namespace umbraco.cms.businesslogic.template return String.Format("", Alias.Replace(" ", "")); - } public List contentPlaceholderIds() @@ -591,8 +595,13 @@ namespace umbraco.cms.businesslogic.template return masterPageContent; } + + public void ImportDesign(string design) { + Design = design; + + /* if (!isMasterPageSyntax(design)) { Design = ConvertToMasterPageSyntax(design); @@ -600,26 +609,17 @@ namespace umbraco.cms.businesslogic.template else { Design = design; - } + }*/ } - private string getMasterPageHeader() - { - return String.Format("<%@ Master Language=\"C#\" MasterPageFile=\"{0}\" AutoEventWireup=\"true\" %>", - currentMasterTemplateFileName()) + Environment.NewLine; - } - - private string currentMasterTemplateFileName() - { - if (MasterTemplate != 0) - return SystemDirectories.Masterpages + "/" + new Template(MasterTemplate).Alias.Replace(" ", "") + ".master"; - else - return UmbracoMasterTemplate; - } - public void SaveMasterPageFile(string masterPageContent) { + //this will trigger the helper and store everything + this.Design = masterPageContent; + + /* + // Add header to master page if it doesn't exist if (!masterPageContent.StartsWith("<%@")) { @@ -681,6 +681,21 @@ namespace umbraco.cms.businesslogic.template // save the file in UTF-8 File.WriteAllText(MasterPageFile, masterPageContent, System.Text.Encoding.UTF8); + * */ + } + + private string getMasterPageHeader() + { + return String.Format("<%@ Master Language=\"C#\" MasterPageFile=\"{0}\" AutoEventWireup=\"true\" %>", + currentMasterTemplateFileName()) + Environment.NewLine; + } + + private string currentMasterTemplateFileName() + { + if (MasterTemplate != 0) + return SystemDirectories.Masterpages + "/" + new Template(MasterTemplate).Alias.Replace(" ", "") + ".master"; + else + return UmbracoMasterTemplate; } private void getAspNetMasterPageForm(ref string design) @@ -802,12 +817,18 @@ namespace umbraco.cms.businesslogic.template } t.Alias = alias; - t.ImportDesign(xmlHelper.GetNodeValue(n.SelectSingleNode("Design"))); return t; } + public static bool HasView(Template t) + { + var path = Umbraco.Core.IO.SystemDirectories.MvcViews + "/" + t.Alias.Replace(" ", "") + ".cshtml"; + return System.IO.File.Exists(Umbraco.Core.IO.IOHelper.MapPath(path)); + } + + #region Events //EVENTS /// diff --git a/src/umbraco.cms/businesslogic/template/ViewHelper.cs b/src/umbraco.cms/businesslogic/template/ViewHelper.cs new file mode 100644 index 0000000000..c3e9306b5e --- /dev/null +++ b/src/umbraco.cms/businesslogic/template/ViewHelper.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Umbraco.Core.IO; + +namespace umbraco.cms.businesslogic.template +{ + class ViewHelper + { + internal static string GetViewFile(Template t) + { + string viewContent = ""; + string path = IOHelper.MapPath(ViewPath(t)); + + if (File.Exists(path)) + { + System.IO.TextReader tr = new StreamReader(path); + viewContent = tr.ReadToEnd(); + tr.Close(); + } + + return viewContent; + } + + internal static string CreateViewFile(Template t, bool overWrite = false) + { + string viewContent = ""; + string path = IOHelper.MapPath(ViewPath(t)); + + if (!File.Exists(path) || overWrite) + viewContent = saveTemplateToFile(t, t.Alias); + else + { + System.IO.TextReader tr = new StreamReader(path); + viewContent = tr.ReadToEnd(); + tr.Close(); + } + + return viewContent; + } + + internal static string saveTemplateToFile(Template template, string currentAlias) + { + var design = EnsureInheritedLayout(template); + System.IO.File.WriteAllText(IOHelper.MapPath(ViewPath(template)), design, Encoding.UTF8); + + return template.Design; + } + + internal static string UpdateViewFile(Template t) + { + var path = IOHelper.MapPath(ViewPath(t)); + System.IO.File.WriteAllText(path, t.Design, Encoding.UTF8); + return t.Design; + } + + public static string ViewPath(Template t) + { + return Umbraco.Core.IO.SystemDirectories.MvcViews + "/" + t.Alias.Replace(" ", "") + ".cshtml"; + } + + + + private static string EnsureInheritedLayout(Template template) + { + string design = template.Design; + + if (string.IsNullOrEmpty(design)) + { + design = @"@inherits Umbraco.Web.Mvc.RenderViewPage +@{ + Layout = null; +}"; + + if (template.MasterTemplate > 0) + design = design.Replace("null", "\"" + new Template(template.MasterTemplate).Alias.Replace(" ", "") + "\""); + + } + + return design; + } + } +} diff --git a/src/umbraco.cms/umbraco.cms.csproj b/src/umbraco.cms/umbraco.cms.csproj index e293cc1585..1db1c56de3 100644 --- a/src/umbraco.cms/umbraco.cms.csproj +++ b/src/umbraco.cms/umbraco.cms.csproj @@ -261,6 +261,8 @@ + +