From a10daaab52f00c5e90ea947918c1c458986559c1 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 10 Oct 2012 20:20:16 +0500 Subject: [PATCH 01/15] Updated code from code review --- src/umbraco.cms/businesslogic/Content.cs | 7 ++++++- src/umbraco.cms/businesslogic/ContentType.cs | 10 +++++----- .../propertytype/PropertyTypeGroup.cs | 20 +++++++++---------- .../propertytype/propertytype.cs | 18 ++++++++--------- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/umbraco.cms/businesslogic/Content.cs b/src/umbraco.cms/businesslogic/Content.cs index 05b22daec3..90b4c35caa 100644 --- a/src/umbraco.cms/businesslogic/Content.cs +++ b/src/umbraco.cms/businesslogic/Content.cs @@ -508,8 +508,13 @@ namespace umbraco.cms.businesslogic /// /// /// The new version Id - protected Guid createNewVersion(DateTime versionDate) + protected Guid createNewVersion(DateTime versionDate = default(DateTime)) { + if (versionDate == default (DateTime)) + { + versionDate = DateTime.Now; + } + ClearLoadedProperties(); Guid newVersion = Guid.NewGuid(); diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 6534972360..ec9dda63bd 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -658,7 +658,7 @@ namespace umbraco.cms.businesslogic SqlHelper.CreateParameter("@parentContentTypeId", this.Id)) > 0; } - public List GetChildTypes() + public IEnumerable GetChildTypes() { var cts = new List(); using (IRecordsReader dr = @@ -694,7 +694,7 @@ namespace umbraco.cms.businesslogic // has a nodetype of this id var contentTypeToRemove = new ContentType(parentContentTypeId); - removeMasterPropertyTypeData(contentTypeToRemove, this); + RemoveMasterPropertyTypeData(contentTypeToRemove, this); SqlHelper.ExecuteNonQuery( "DELETE FROM [cmsContentType2ContentType] WHERE parentContentTypeId = @parentContentTypeId AND childContentTypeId = @childContentTypeId", @@ -704,7 +704,7 @@ namespace umbraco.cms.businesslogic } } - private void removeMasterPropertyTypeData(ContentType contentTypeToRemove, ContentType currentContentType) + private void RemoveMasterPropertyTypeData(ContentType contentTypeToRemove, ContentType currentContentType) { foreach (var pt in contentTypeToRemove.PropertyTypes) { @@ -723,10 +723,10 @@ namespace umbraco.cms.businesslogic } // remove sub data too foreach(var ct in currentContentType.GetChildTypes()) - removeMasterPropertyTypeData(contentTypeToRemove, ct); + RemoveMasterPropertyTypeData(contentTypeToRemove, ct); } - public List PropertyTypeGroups + public IEnumerable PropertyTypeGroups { get { return PropertyTypeGroup.GetPropertyTypeGroupsFromContentType(Id); } } diff --git a/src/umbraco.cms/businesslogic/propertytype/PropertyTypeGroup.cs b/src/umbraco.cms/businesslogic/propertytype/PropertyTypeGroup.cs index c2a3c138fe..5f322abdef 100644 --- a/src/umbraco.cms/businesslogic/propertytype/PropertyTypeGroup.cs +++ b/src/umbraco.cms/businesslogic/propertytype/PropertyTypeGroup.cs @@ -37,20 +37,20 @@ namespace umbraco.cms.businesslogic.propertytype SortOrder = -1; // we set this to -1 so in the save method we can get the current highest sortorder in case it's not sat after init (ie. if you want to force a sortOrder) } - public List GetPropertyTypes(List contentTypeIds) + public IEnumerable GetPropertyTypes(List contentTypeIds) { return PropertyType.GetPropertyTypesByGroup(Id, contentTypeIds); } - public List GetPropertyTypes() + public IEnumerable GetPropertyTypes() { return PropertyType.GetPropertyTypesByGroup(Id); } //TODO: Verify support for master doctypes / mixins! - public List GetPropertyTypeGroups() + public IEnumerable GetPropertyTypeGroups() { - List ptgs = new List(); + var ptgs = new List(); using (IRecordsReader dr = SqlHelper.ExecuteReader(@" SELECT @@ -86,7 +86,7 @@ namespace umbraco.cms.businesslogic.propertytype id = @id ", SqlHelper.CreateParameter("@id", Id), - SqlHelper.CreateParameter("@parentGroupId", convertParentId(ParentId)), + SqlHelper.CreateParameter("@parentGroupId", ConvertParentId(ParentId)), SqlHelper.CreateParameter("@contentTypeId", ContentTypeId), SqlHelper.CreateParameter("@sortOrder", SortOrder), SqlHelper.CreateParameter("@name", Name) @@ -106,7 +106,7 @@ namespace umbraco.cms.businesslogic.propertytype VALUES (@parentGroupId, @contentTypeId, @sortOrder, @name) ", - SqlHelper.CreateParameter("@parentGroupId", convertParentId(ParentId)), + SqlHelper.CreateParameter("@parentGroupId", ConvertParentId(ParentId)), SqlHelper.CreateParameter("@contentTypeId", ContentTypeId), SqlHelper.CreateParameter("@sortOrder", SortOrder), SqlHelper.CreateParameter("@name", Name) @@ -133,7 +133,7 @@ namespace umbraco.cms.businesslogic.propertytype SqlHelper.CreateParameter("@id", Id)); } - public void Load() + internal void Load() { using (IRecordsReader dr = SqlHelper.ExecuteReader(@" @@ -164,9 +164,9 @@ namespace umbraco.cms.businesslogic.propertytype return ptg; } - public static List GetPropertyTypeGroupsFromContentType(int contentTypeId) + public static IEnumerable GetPropertyTypeGroupsFromContentType(int contentTypeId) { - List ptgs = new List(); + var ptgs = new List(); using (IRecordsReader dr = SqlHelper.ExecuteReader(@" SELECT @@ -185,7 +185,7 @@ namespace umbraco.cms.businesslogic.propertytype return ptgs; } - private object convertParentId(int parentId) + private object ConvertParentId(int parentId) { if (parentId == 0) return DBNull.Value; diff --git a/src/umbraco.cms/businesslogic/propertytype/propertytype.cs b/src/umbraco.cms/businesslogic/propertytype/propertytype.cs index 365529f8ab..8d3fcd09c7 100644 --- a/src/umbraco.cms/businesslogic/propertytype/propertytype.cs +++ b/src/umbraco.cms/businesslogic/propertytype/propertytype.cs @@ -311,11 +311,11 @@ namespace umbraco.cms.businesslogic.propertytype public static PropertyType[] GetAll() { - List result = GetPropertyTypes(); + var result = GetPropertyTypes(); return result.ToArray(); } - public static List GetPropertyTypes() + public static IEnumerable GetPropertyTypes() { var result = new List(); using (IRecordsReader dr = @@ -331,12 +331,12 @@ namespace umbraco.cms.businesslogic.propertytype return result; } - public static List GetPropertyTypesByGroup(int groupId, List contentTypeIds) + public static IEnumerable GetPropertyTypesByGroup(int groupId, List contentTypeIds) { - return GetPropertyTypesByGroup(groupId).FindAll(x => contentTypeIds.Contains(x.ContentTypeId)); + return GetPropertyTypesByGroup(groupId).Where(x => contentTypeIds.Contains(x.ContentTypeId)); } - public static List GetPropertyTypesByGroup(int groupId) + public static IEnumerable GetPropertyTypesByGroup(int groupId) { var result = new List(); using (IRecordsReader dr = @@ -382,11 +382,11 @@ namespace umbraco.cms.businesslogic.propertytype FlushCache(); // clean all properties on inherited document types (if this propertytype is removed from a master) - cleanPropertiesOnDeletion(_contenttypeid); + CleanPropertiesOnDeletion(_contenttypeid); // DocumentType.GetAllAsList().FindAll(dt => dt.MasterContentType == _contenttypeid).ForEach(dt => cleanPropertiesOnDeletion(dt.Id)); // Delete all properties of propertytype - cleanPropertiesOnDeletion(_contenttypeid); + CleanPropertiesOnDeletion(_contenttypeid); // Delete PropertyType .. SqlHelper.ExecuteNonQuery("Delete from cmsPropertyType where id = " + Id); @@ -409,12 +409,12 @@ namespace umbraco.cms.businesslogic.propertytype } } - private void cleanPropertiesOnDeletion(int contentTypeId) + private void CleanPropertiesOnDeletion(int contentTypeId) { // first delete from all master document types //TODO: Verify no endless loops with mixins DocumentType.GetAllAsList().FindAll(dt => dt.MasterContentTypes.Contains(contentTypeId)).ForEach( - dt => cleanPropertiesOnDeletion(dt.Id)); + dt => CleanPropertiesOnDeletion(dt.Id)); // then remove from the current doc type Content[] objs = Content.getContentOfContentType(new ContentType(contentTypeId)); From 77db6cad018bbb9baf1a34d47156d099b26cf126 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 10 Oct 2012 20:44:29 +0500 Subject: [PATCH 02/15] Fixes issues with last commmit. Fixes: U4-786 - made some things public --- src/Umbraco.Core/IO/IOHelper.cs | 12 ++++++------ src/Umbraco.Core/IO/SystemDirectories.cs | 3 ++- src/Umbraco.Core/XmlHelper.cs | 14 +++++++------- src/umbraco.businesslogic/IO/IOHelper.cs | 3 ++- src/umbraco.cms/businesslogic/ContentType.cs | 15 ++++++++++----- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index d5a5e2e452..5ee613cccd 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -13,7 +13,7 @@ using Umbraco.Core.Logging; namespace Umbraco.Core.IO { - internal static class IOHelper + public static class IOHelper { private static string _rootDir = ""; @@ -52,7 +52,7 @@ namespace Umbraco.Core.IO } [Obsolete("Use Umbraco.Web.Templates.TemplateUtilities.ResolveUrlsFromTextString instead, this method on this class will be removed in future versions")] - public static string ResolveUrlsFromTextString(string text) + internal static string ResolveUrlsFromTextString(string text) { if (UmbracoSettings.ResolveUrlsFromTextString) { @@ -117,7 +117,8 @@ namespace Umbraco.Core.IO } //use a tilde character instead of the complete path - public static string ReturnPath(string settingsKey, string standardPath, bool useTilde) + [Obsolete("This method is no longer in use and will be removed in future versions")] + internal static string ReturnPath(string settingsKey, string standardPath, bool useTilde) { string retval = ConfigurationManager.AppSettings[settingsKey]; @@ -127,14 +128,13 @@ namespace Umbraco.Core.IO return retval.TrimEnd('/'); } - - public static string ReturnPath(string settingsKey, string standardPath) + [Obsolete("This method is no longer in use and will be removed in future versions")] + internal static string ReturnPath(string settingsKey, string standardPath) { return ReturnPath(settingsKey, standardPath, false); } - /// /// Validates if the current filepath matches a directory where the user is allowed to edit a file /// diff --git a/src/Umbraco.Core/IO/SystemDirectories.cs b/src/Umbraco.Core/IO/SystemDirectories.cs index 521407898a..e7f6b29c60 100644 --- a/src/Umbraco.Core/IO/SystemDirectories.cs +++ b/src/Umbraco.Core/IO/SystemDirectories.cs @@ -86,8 +86,9 @@ namespace Umbraco.Core.IO } } + //have changed to internal so nobody uses this anymore since this is a new class. [Obsolete("Please use MacroScripts instead!", true)] - public static string Python + internal static string Python { get { diff --git a/src/Umbraco.Core/XmlHelper.cs b/src/Umbraco.Core/XmlHelper.cs index 10b2d8a09d..0a3d16e9c8 100644 --- a/src/Umbraco.Core/XmlHelper.cs +++ b/src/Umbraco.Core/XmlHelper.cs @@ -11,7 +11,7 @@ namespace Umbraco.Core /// /// The XmlHelper class contains general helper methods for working with xml in umbraco. /// - internal class XmlHelper + public class XmlHelper { /// @@ -20,7 +20,7 @@ namespace Umbraco.Core /// The text. /// The XML doc. /// - public static XmlNode ImportXmlNodeFromText(string text, ref XmlDocument xmlDoc) + internal static XmlNode ImportXmlNodeFromText(string text, ref XmlDocument xmlDoc) { xmlDoc.LoadXml(text); return xmlDoc.FirstChild; @@ -92,7 +92,7 @@ namespace Umbraco.Core /// /// The XmlNode. /// the value as a string - public static string GetNodeValue(XmlNode n) + internal static string GetNodeValue(XmlNode n) { var value = string.Empty; if (n == null || n.FirstChild == null) @@ -108,7 +108,7 @@ namespace Umbraco.Core /// /// true if the specified string appears to be XML; otherwise, false. /// - public static bool CouldItBeXml(string xml) + internal static bool CouldItBeXml(string xml) { if (!string.IsNullOrEmpty(xml)) { @@ -131,7 +131,7 @@ namespace Umbraco.Core /// Name of the root. /// Name of the element. /// Returns an System.Xml.XmlDocument representation of the delimited string data. - public static XmlDocument Split(string data, string[] separator, string rootName, string elementName) + internal static XmlDocument Split(string data, string[] separator, string rootName, string elementName) { return Split(new XmlDocument(), data, separator, rootName, elementName); } @@ -145,7 +145,7 @@ namespace Umbraco.Core /// Name of the root node. /// Name of the element node. /// Returns an System.Xml.XmlDocument representation of the delimited string data. - public static XmlDocument Split(XmlDocument xml, string data, string[] separator, string rootName, string elementName) + internal static XmlDocument Split(XmlDocument xml, string data, string[] separator, string rootName, string elementName) { // load new XML document. xml.LoadXml(string.Concat("<", rootName, "/>")); @@ -174,7 +174,7 @@ namespace Umbraco.Core /// /// /// - public static Dictionary GetAttributesFromElement(string tag) + internal static Dictionary GetAttributesFromElement(string tag) { var m = Regex.Matches(tag, "(?\\S*)=\"(?[^\"]*)\"", diff --git a/src/umbraco.businesslogic/IO/IOHelper.cs b/src/umbraco.businesslogic/IO/IOHelper.cs index eb99389fcc..8a7e10d9eb 100644 --- a/src/umbraco.businesslogic/IO/IOHelper.cs +++ b/src/umbraco.businesslogic/IO/IOHelper.cs @@ -53,12 +53,13 @@ namespace umbraco.IO } //use a tilde character instead of the complete path + [Obsolete("This method is no longer in use and will be removed in future versions")] public static string returnPath(string settingsKey, string standardPath, bool useTilde) { return Umbraco.Core.IO.IOHelper.ReturnPath(settingsKey, standardPath, useTilde); } - + [Obsolete("This method is no longer in use and will be removed in future versions")] public static string returnPath(string settingsKey, string standardPath) { return Umbraco.Core.IO.IOHelper.ReturnPath(settingsKey, standardPath); diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index ec9dda63bd..8367e8335b 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -1170,7 +1170,7 @@ namespace umbraco.cms.businesslogic private void InitializeVirtualTabs() { m_VirtualTabs = new List(); - foreach (PropertyTypeGroup ptg in PropertyTypeGroups.FindAll(x => x.ParentId == 0 && x.ContentTypeId == this.Id)) + foreach (PropertyTypeGroup ptg in PropertyTypeGroups.Where(x => x.ParentId == 0 && x.ContentTypeId == this.Id)) m_VirtualTabs.Add(new Tab(ptg.Id, ptg.Name, ptg.SortOrder, this)); // Master Content Type @@ -1335,19 +1335,24 @@ namespace umbraco.cms.businesslogic { // NH, temp fix for 4.9 to use the new PropertyTypeGroup API - List pts = PropertyTypeGroup.GetPropertyTypeGroup(this.Id).GetPropertyTypes(); + var pts = PropertyTypeGroup.GetPropertyTypeGroup(this.Id).GetPropertyTypes(); if (includeInheritedProperties) { // we need to cms.businesslogic.ContentType ct = cms.businesslogic.ContentType.GetContentType(contentTypeId); return - pts.FindAll( + pts.Where( x => ct.MasterContentTypes.Contains( x.ContentTypeId) || x.ContentTypeId == contentTypeId).ToArray(); } - return pts.FindAll(x => x.ContentTypeId == contentTypeId).ToArray(); + return pts.Where(x => x.ContentTypeId == contentTypeId).ToArray(); + + //TODO: Why is this code still here?? revision: 1bd01ec17bf9 + // shouldn't this code be removed/commented out or something????? + // the below code is completely unreachable. + // zb-00040 #29889 : fix cache key issues! // now maintaining a cache of local properties per contentTypeId, then merging when required @@ -1388,7 +1393,7 @@ namespace umbraco.cms.businesslogic // while (dr.Read()) // tmp1.Add(PropertyType.GetPropertyType(dr.GetInt("id"))); // } - return tmp1; + return tmp1.ToList(); }); tmp.AddRange(ptypes); From 83c53333c63bd2603449dad7db81434b798c272f Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 10 Oct 2012 20:45:51 +0500 Subject: [PATCH 03/15] Removed GetDictionaryValue from RenderViewPage, this can be accessed through the @Umbraco property. --- src/Umbraco.Web/Mvc/RenderViewPage.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/Umbraco.Web/Mvc/RenderViewPage.cs b/src/Umbraco.Web/Mvc/RenderViewPage.cs index 36ad6d51d4..8d3b450b75 100644 --- a/src/Umbraco.Web/Mvc/RenderViewPage.cs +++ b/src/Umbraco.Web/Mvc/RenderViewPage.cs @@ -51,17 +51,7 @@ namespace Umbraco.Web.Mvc /// /// Returns the a DynamicPublishedContent object /// - public dynamic CurrentPage { get; private set; } - - /// - /// Returns the dictionary value for the key specified - /// - /// - /// - public string GetDictionaryValue(string key) - { - return Umbraco.GetDictionaryValue(key); - } + public dynamic CurrentPage { get; private set; } private UmbracoHelper _helper; From 16b47539b47b262563609daf729757d7b0482050 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 10 Oct 2012 22:33:49 +0500 Subject: [PATCH 04/15] Fixes up an issue relating to U4-1010 but is only the initial fix, now need to look at the changing the package installation process to ensure the templte files are there before the template db entries. --- .../template/MasterpageHelper.cs | 8 ++- .../businesslogic/template/Template.cs | 62 +++++++++++++++---- .../businesslogic/template/ViewHelper.cs | 6 ++ 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs index 700d8b4165..7ef910948a 100644 --- a/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs +++ b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs @@ -12,7 +12,13 @@ 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) + + internal static bool MasterPageExists(Template t) + { + return File.Exists(t.MasterPageFile); + } + + internal static string CreateMasterpageFile(Template t, bool overWrite = false) { string masterpageContent = ""; diff --git a/src/umbraco.cms/businesslogic/template/Template.cs b/src/umbraco.cms/businesslogic/template/Template.cs index bc49fee581..2cf8fbba4d 100644 --- a/src/umbraco.cms/businesslogic/template/Template.cs +++ b/src/umbraco.cms/businesslogic/template/Template.cs @@ -317,17 +317,49 @@ namespace umbraco.cms.businesslogic.template return DocumentType.GetAllAsList().Where(x => x.allowedTemplates.Select(t => t.Id).Contains(this.Id)); } + /// + /// This checks what the default rendering engine is set in config but then also ensures that there isn't already + /// a template that exists in the opposite rendering engine's template folder, then returns the appropriate + /// rendering engine to use. + /// + /// + /// + /// + /// The reason this is required is because for example, if you have a master page file already existing under ~/masterpages/Blah.aspx + /// and then you go to create a template in the tree called Blah and the default rendering engine is MVC, it will create a Blah.cshtml + /// empty template in ~/Views. This means every page that is using Blah will go to MVC and render an empty page. + /// This is mostly related to installing packages since packages install file templates to the file system and then create the + /// templates in business logic. Without this, it could cause the wrong rendering engine to be used for a package. + /// + private static RenderingEngine DetermineRenderingEngine(Template t) + { + var engine = Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine; + switch (engine) + { + case RenderingEngine.Mvc: + //check if there's a view in ~/masterpages + if (MasterpageHelper.MasterPageExists(t) && !ViewHelper.ViewExists(t)) + { + //change this to webforms since there's already a file there for this template alias + engine = RenderingEngine.WebForms; + } + break; + case RenderingEngine.WebForms: + //check if there's a view in ~/views + if (ViewHelper.ViewExists(t) && !MasterpageHelper.MasterPageExists(t)) + { + //change this to mvc since there's already a file there for this template alias + engine = RenderingEngine.Mvc; + } + break; + } + return engine; + } + public static Template MakeNew(string Name, BusinessLogic.User u, Template master) { Template t = MakeNew(Name, u); - t.MasterTemplate = master.Id; - - if (Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine == RenderingEngine.Mvc) - ViewHelper.CreateViewFile(t, true); - else - MasterpageHelper.CreateMasterpageFile(t, true); - - + t.MasterTemplate = master.Id; /* if (UmbracoSettings.UseAspNetMasterPages) @@ -374,11 +406,15 @@ namespace umbraco.cms.businesslogic.template NewEventArgs e = new NewEventArgs(); t.OnNew(e); - if (Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine == RenderingEngine.Mvc) - t._design = ViewHelper.CreateViewFile(t); - else - t._design = MasterpageHelper.CreateMasterpageFile(t); - + switch (DetermineRenderingEngine(t)) + { + case RenderingEngine.Mvc: + ViewHelper.CreateViewFile(t, true); + break; + case RenderingEngine.WebForms: + MasterpageHelper.CreateMasterpageFile(t, true); + break; + } return t; } diff --git a/src/umbraco.cms/businesslogic/template/ViewHelper.cs b/src/umbraco.cms/businesslogic/template/ViewHelper.cs index c915e18d9f..aa9e34711e 100644 --- a/src/umbraco.cms/businesslogic/template/ViewHelper.cs +++ b/src/umbraco.cms/businesslogic/template/ViewHelper.cs @@ -9,6 +9,12 @@ namespace umbraco.cms.businesslogic.template { class ViewHelper { + internal static bool ViewExists(Template t) + { + string path = IOHelper.MapPath(ViewPath(t)); + return File.Exists(path); + } + internal static string GetViewFile(Template t) { string viewContent = ""; From 29614d6b03808a5eed91e50cb1e42c5adad69a4c Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 10 Oct 2012 23:31:54 +0500 Subject: [PATCH 05/15] Fixes: U4-1010, U4-1009 -> issues relating to template business logic changes which checks for default rendering engine (MVC vs WebForms) and fixes package installation issues associated with them. --- .../developer/Packages/installer.aspx.cs | 121 +++++++++--------- .../businesslogic/Packager/Installer.cs | 5 +- .../template/MasterpageHelper.cs | 2 +- .../businesslogic/template/Template.cs | 103 ++++++++------- 4 files changed, 119 insertions(+), 112 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs index c64f125608..54a6ecb348 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs @@ -22,11 +22,10 @@ namespace umbraco.presentation.developer.packages /// public partial class Installer : BasePages.UmbracoEnsuredPage { - private Control configControl; - private cms.businesslogic.packager.repositories.Repository repo; - - private cms.businesslogic.packager.Installer p = new cms.businesslogic.packager.Installer(); - private string tempFileName = ""; + private Control _configControl; + private cms.businesslogic.packager.repositories.Repository _repo; + private readonly cms.businesslogic.packager.Installer _installer = new cms.businesslogic.packager.Installer(); + private string _tempFileName = ""; protected void Page_Load(object sender, System.EventArgs e) { @@ -47,34 +46,34 @@ namespace umbraco.presentation.developer.packages //if we are actually in the middle of installing something... if (!String.IsNullOrEmpty(helper.Request("installing"))) { - hideAllPanes(); + HideAllPanes(); pane_installing.Visible = true; - processInstall(helper.Request("installing")); + ProcessInstall(helper.Request("installing")); } else if (!String.IsNullOrEmpty(helper.Request("guid")) && !String.IsNullOrEmpty(helper.Request("repoGuid"))) { //we'll fetch the local information we have about our repo, to find out what webservice to query. - repo = cms.businesslogic.packager.repositories.Repository.getByGuid(helper.Request("repoGuid")); + _repo = cms.businesslogic.packager.repositories.Repository.getByGuid(helper.Request("repoGuid")); - if (repo.HasConnection()) + if (_repo.HasConnection()) { //from the webservice we'll fetch some info about the package. - cms.businesslogic.packager.repositories.Package pack = repo.Webservice.PackageByGuid(helper.Request("guid")); + cms.businesslogic.packager.repositories.Package pack = _repo.Webservice.PackageByGuid(helper.Request("guid")); //if the package is protected we will ask for the users credentials. (this happens every time they try to fetch anything) if (!pack.Protected) { //if it isn't then go straigt to the accept licens screen - tempFile.Value = p.Import(repo.fetch(helper.Request("guid"))); - updateSettings(); + tempFile.Value = _installer.Import(_repo.fetch(helper.Request("guid"))); + UpdateSettings(); } else if (!IsPostBack) { //Authenticate against the repo - hideAllPanes(); + HideAllPanes(); pane_authenticate.Visible = true; } @@ -83,7 +82,7 @@ namespace umbraco.presentation.developer.packages { fb.Style.Add("margin-top", "7px"); fb.type = global::umbraco.uicontrols.Feedback.feedbacktype.error; - fb.Text = "No connection to repository. Runway could not be installed as there was no connection to: '" + repo.RepositoryUrl + "'"; + fb.Text = "No connection to repository. Runway could not be installed as there was no connection to: '" + _repo.RepositoryUrl + "'"; pane_upload.Visible = false; } } @@ -99,11 +98,11 @@ namespace umbraco.presentation.developer.packages { try { - tempFileName = Guid.NewGuid().ToString() + ".umb"; - string fileName = SystemDirectories.Data + System.IO.Path.DirectorySeparatorChar + tempFileName; + _tempFileName = Guid.NewGuid().ToString() + ".umb"; + string fileName = SystemDirectories.Data + System.IO.Path.DirectorySeparatorChar + _tempFileName; file1.PostedFile.SaveAs(IOHelper.MapPath(fileName)); - tempFile.Value = p.Import(tempFileName); - updateSettings(); + tempFile.Value = _installer.Import(_tempFileName); + UpdateSettings(); } catch (Exception ex) { @@ -116,75 +115,75 @@ namespace umbraco.presentation.developer.packages protected void fetchProtectedPackage(object sender, EventArgs e) { //we auth against the webservice. This key will be used to fetch the protected package. - string memberGuid = repo.Webservice.authenticate(tb_email.Text, library.md5(tb_password.Text)); + string memberGuid = _repo.Webservice.authenticate(tb_email.Text, library.md5(tb_password.Text)); //if we auth correctly and get a valid key back, we will fetch the file from the repo webservice. if (!string.IsNullOrEmpty(memberGuid)) { - tempFile.Value = p.Import(repo.fetch(helper.Request("guid"), memberGuid)); - updateSettings(); + tempFile.Value = _installer.Import(_repo.fetch(helper.Request("guid"), memberGuid)); + UpdateSettings(); } } //this loads the accept license screen - private void updateSettings() + private void UpdateSettings() { - hideAllPanes(); + HideAllPanes(); pane_acceptLicense.Visible = true; - pane_acceptLicenseInner.Text = "Installing the package: " + p.Name; - Panel1.Text = "Installing the package: " + p.Name; + pane_acceptLicenseInner.Text = "Installing the package: " + _installer.Name; + Panel1.Text = "Installing the package: " + _installer.Name; - if (p.ContainsUnsecureFiles && repo == null) + if (_installer.ContainsUnsecureFiles && _repo == null) { pp_unsecureFiles.Visible = true; - foreach (string str in p.UnsecureFiles) + foreach (string str in _installer.UnsecureFiles) { lt_files.Text += "
  • " + str + "
  • "; } } - if (p.ContainsMacroConflict) + if (_installer.ContainsMacroConflict) { pp_macroConflicts.Visible = true; - foreach (var item in p.ConflictingMacroAliases) + foreach (var item in _installer.ConflictingMacroAliases) { ltrMacroAlias.Text += "
  • " + item.Key + " (Alias: " + item.Value + ")
  • "; } } - if (p.ContainsTemplateConflicts) + if (_installer.ContainsTemplateConflicts) { pp_templateConflicts.Visible = true; - foreach (var item in p.ConflictingTemplateAliases) + foreach (var item in _installer.ConflictingTemplateAliases) { ltrTemplateAlias.Text += "
  • " + item.Key + " (Alias: " + item.Value + ")
  • "; } } - if (p.ContainsStyleSheeConflicts) + if (_installer.ContainsStyleSheeConflicts) { pp_stylesheetConflicts.Visible = true; - foreach (var item in p.ConflictingStyleSheetNames) + foreach (var item in _installer.ConflictingStyleSheetNames) { ltrStylesheetNames.Text += "
  • " + item.Key + " (Alias: " + item.Value + ")
  • "; } } - LabelName.Text = p.Name + " Version: " + p.Version; - LabelMore.Text = "" + p.Url + ""; - LabelAuthor.Text = "" + p.Author + ""; - LabelLicense.Text = "" + p.License + ""; + LabelName.Text = _installer.Name + " Version: " + _installer.Version; + LabelMore.Text = "" + _installer.Url + ""; + LabelAuthor.Text = "" + _installer.Author + ""; + LabelLicense.Text = "" + _installer.License + ""; - if (p.ReadMe != "") - readme.Text = "
    " + library.ReplaceLineBreaks(library.StripHtml(p.ReadMe)) + "
    "; + if (_installer.ReadMe != "") + readme.Text = "
    " + library.ReplaceLineBreaks(library.StripHtml(_installer.ReadMe)) + "
    "; else readme.Text = "No information
    "; } - private void processInstall(string currentStep) + private void ProcessInstall(string currentStep) { string dir = helper.Request("dir"); int packageId = 0; @@ -193,20 +192,20 @@ namespace umbraco.presentation.developer.packages //first load in the config from the temporary directory //this will ensure that the installer have access to all the new files and the package manifest - p.LoadConfig(dir); + _installer.LoadConfig(dir); switch (currentStep) { case "businesslogic": - p.InstallBusinessLogic(packageId, dir); + _installer.InstallBusinessLogic(packageId, dir); //making sure that publishing actions performed from the cms layer gets pushed to the presentation library.RefreshContent(); - if (p.Control != null && p.Control != "") + if (_installer.Control != null && _installer.Control != "") { Response.Redirect("installer.aspx?installing=customInstaller&dir=" + dir + "&pId=" + packageId.ToString()); } @@ -216,26 +215,26 @@ namespace umbraco.presentation.developer.packages } break; case "customInstaller": - if (p.Control != null && p.Control != "") + if (_installer.Control != null && _installer.Control != "") { - hideAllPanes(); + HideAllPanes(); - configControl = new System.Web.UI.UserControl().LoadControl(SystemDirectories.Root + p.Control); - configControl.ID = "packagerConfigControl"; + _configControl = new System.Web.UI.UserControl().LoadControl(SystemDirectories.Root + _installer.Control); + _configControl.ID = "packagerConfigControl"; - pane_optional.Controls.Add(configControl); + pane_optional.Controls.Add(_configControl); pane_optional.Visible = true; } else { - hideAllPanes(); + HideAllPanes(); pane_success.Visible = true; BasePage.Current.ClientTools.ReloadActionNode(true, true); } break; case "finished": - hideAllPanes(); - string url = p.Url; + HideAllPanes(); + string url = _installer.Url; string packageViewUrl = "installedPackage.aspx?id=" + packageId.ToString(); bt_viewInstalledPackage.OnClientClick = "document.location = '" + packageViewUrl + "'; return false;"; @@ -247,7 +246,7 @@ namespace umbraco.presentation.developer.packages pane_success.Visible = true; BasePage.Current.ClientTools.ReloadActionNode(true, true); - p.InstallCleanUp(packageId, dir); + _installer.InstallCleanUp(packageId, dir); //clear the tree cache ClientTools.ClearClientTreeCache() @@ -269,30 +268,30 @@ namespace umbraco.presentation.developer.packages //we will now create the installer manifest, which means that umbraco can register everything that gets added to the system //this returns an id of the manifest. - p.LoadConfig(tempFile.Value); + _installer.LoadConfig(tempFile.Value); - int pId = p.CreateManifest(tempFile.Value, helper.Request("guid"), helper.Request("repoGuid")); + int pId = _installer.CreateManifest(tempFile.Value, helper.Request("guid"), helper.Request("repoGuid")); //and then copy over the files. This will take some time if it contains .dlls that will reboot the system.. - p.InstallFiles(pId, tempFile.Value); + _installer.InstallFiles(pId, tempFile.Value); Response.Redirect("installer.aspx?installing=businesslogic&dir=" + tempFile.Value + "&pId=" + pId.ToString()); } - private void drawConfig() + private void DrawConfig() { - hideAllPanes(); + HideAllPanes(); - configControl = new System.Web.UI.UserControl().LoadControl(SystemDirectories.Root + helper.Request("config")); - configControl.ID = "packagerConfigControl"; + _configControl = new System.Web.UI.UserControl().LoadControl(SystemDirectories.Root + helper.Request("config")); + _configControl.ID = "packagerConfigControl"; - pane_optional.Controls.Add(configControl); + pane_optional.Controls.Add(_configControl); pane_optional.Visible = true; } - private void hideAllPanes() + private void HideAllPanes() { pane_authenticate.Visible = false; pane_acceptLicense.Visible = false; diff --git a/src/umbraco.cms/businesslogic/Packager/Installer.cs b/src/umbraco.cms/businesslogic/Packager/Installer.cs index 8b51588f54..b55ea4715d 100644 --- a/src/umbraco.cms/businesslogic/Packager/Installer.cs +++ b/src/umbraco.cms/businesslogic/Packager/Installer.cs @@ -332,7 +332,10 @@ namespace umbraco.cms.businesslogic.packager if (saveNeeded) { insPack.Save(); saveNeeded = false; } - // Add master templates + //NOTE: SD: I'm pretty sure the only thing the below script does is ensure that the Master template Id is set + // in the database, but this is also duplicating the saving of the design content since the above Template.Import + // already does this. I've left this for now because I'm not sure the reprocussions of removing it but seems there + // is a lot of excess database calls happening here. foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) { string master = xmlHelper.GetNodeValue(n.SelectSingleNode("Master")); template.Template t = template.Template.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Alias"))); diff --git a/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs index 7ef910948a..3eb450ef0d 100644 --- a/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs +++ b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs @@ -137,7 +137,7 @@ namespace umbraco.cms.businesslogic.template return masterPageContent; } - private static bool IsMasterPageSyntax(string code) + internal static bool IsMasterPageSyntax(string code) { return code.Contains("<%@ Master") || code.Contains(" x.allowedTemplates.Select(t => t.Id).Contains(this.Id)); } - /// - /// This checks what the default rendering engine is set in config but then also ensures that there isn't already - /// a template that exists in the opposite rendering engine's template folder, then returns the appropriate - /// rendering engine to use. - /// - /// - /// - /// - /// The reason this is required is because for example, if you have a master page file already existing under ~/masterpages/Blah.aspx - /// and then you go to create a template in the tree called Blah and the default rendering engine is MVC, it will create a Blah.cshtml - /// empty template in ~/Views. This means every page that is using Blah will go to MVC and render an empty page. - /// This is mostly related to installing packages since packages install file templates to the file system and then create the - /// templates in business logic. Without this, it could cause the wrong rendering engine to be used for a package. - /// - private static RenderingEngine DetermineRenderingEngine(Template t) + /// + /// This checks what the default rendering engine is set in config but then also ensures that there isn't already + /// a template that exists in the opposite rendering engine's template folder, then returns the appropriate + /// rendering engine to use. + /// + /// + /// If a template body is specified we'll check if it contains master page markup, if it does we'll auto assume its webforms + /// + /// + /// The reason this is required is because for example, if you have a master page file already existing under ~/masterpages/Blah.aspx + /// and then you go to create a template in the tree called Blah and the default rendering engine is MVC, it will create a Blah.cshtml + /// empty template in ~/Views. This means every page that is using Blah will go to MVC and render an empty page. + /// This is mostly related to installing packages since packages install file templates to the file system and then create the + /// templates in business logic. Without this, it could cause the wrong rendering engine to be used for a package. + /// + private static RenderingEngine DetermineRenderingEngine(Template t, string design = null) { var engine = Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine; + + if (!design.IsNullOrWhiteSpace() && MasterpageHelper.IsMasterPageSyntax(design)) + { + //there is a design but its definitely a webforms design + return RenderingEngine.WebForms; + } + switch (engine) { case RenderingEngine.Mvc: @@ -354,11 +357,11 @@ namespace umbraco.cms.businesslogic.template break; } return engine; - } + } - public static Template MakeNew(string Name, BusinessLogic.User u, Template master) + public static Template MakeNew(string Name, BusinessLogic.User u, Template master, string design = null) { - Template t = MakeNew(Name, u); + Template t = MakeNew(Name, u, design); t.MasterTemplate = master.Id; /* @@ -378,7 +381,7 @@ namespace umbraco.cms.businesslogic.template return t; } - public static Template MakeNew(string name, BusinessLogic.User u) + public static Template MakeNew(string name, BusinessLogic.User u, string design = null) { // CMSNode MakeNew(int parentId, Guid objectType, int userId, int level, string text, Guid uniqueID) @@ -406,7 +409,7 @@ namespace umbraco.cms.businesslogic.template NewEventArgs e = new NewEventArgs(); t.OnNew(e); - switch (DetermineRenderingEngine(t)) + switch (DetermineRenderingEngine(t, design)) { case RenderingEngine.Mvc: ViewHelper.CreateViewFile(t, true); @@ -416,6 +419,12 @@ namespace umbraco.cms.businesslogic.template break; } + //if a design is supplied ensure it is updated. + if (!design.IsNullOrWhiteSpace()) + { + t.ImportDesign(design); + } + return t; } @@ -614,17 +623,17 @@ namespace umbraco.cms.businesslogic.template public string EnsureMasterPageSyntax(string masterPageContent) { - replaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", true); - replaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", false); + 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); + 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("", getAspNetMasterPageContentContainer()).Replace("", getAspNetMasterPageContentContainer()); + masterPageContent = masterPageContent.Replace("", GetAspNetMasterPageContentContainer()).Replace("", GetAspNetMasterPageContentContainer()); // Parse the design for aspnet forms - getAspNetMasterPageForm(ref masterPageContent); + GetAspNetMasterPageForm(ref masterPageContent); masterPageContent = masterPageContent.Replace("", ""); // Parse the design for aspnet heads masterPageContent = masterPageContent.Replace("", String.Format("", Alias.Replace(" ", ""))); @@ -719,15 +728,9 @@ namespace umbraco.cms.businesslogic.template 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() + private string CurrentMasterTemplateFileName() { if (MasterTemplate != 0) return SystemDirectories.Masterpages + "/" + new Template(MasterTemplate).Alias.Replace(" ", "") + ".master"; @@ -735,9 +738,9 @@ namespace umbraco.cms.businesslogic.template return UmbracoMasterTemplate; } - private void getAspNetMasterPageForm(ref string design) + private void GetAspNetMasterPageForm(ref string design) { - Match formElement = Regex.Match(design, getElementRegExp("?ASPNET_FORM", false), RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); + Match formElement = Regex.Match(design, GetElementRegExp("?ASPNET_FORM", false), RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); if (formElement != null && formElement.Value != "") { string formReplace = String.Format("
    ", Alias.Replace(" ", "")); @@ -749,17 +752,17 @@ namespace umbraco.cms.businesslogic.template } } - private string getAspNetMasterPageContentContainer() + private string GetAspNetMasterPageContentContainer() { return String.Format( "", Alias.Replace(" ", "")); } - private void replaceElement(ref string design, string elementName, string newElementName, bool checkForQuotes) + private void ReplaceElement(ref string design, string elementName, string newElementName, bool checkForQuotes) { MatchCollection m = - Regex.Matches(design, getElementRegExp(elementName, checkForQuotes), + Regex.Matches(design, GetElementRegExp(elementName, checkForQuotes), RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); foreach (Match match in m) @@ -798,7 +801,7 @@ namespace umbraco.cms.businesslogic.template - private string getElementRegExp(string elementName, bool checkForQuotes) + private string GetElementRegExp(string elementName, bool checkForQuotes) { if (checkForQuotes) return String.Format("\"<[^>\\s]*\\b{0}(\\b[^>]*)>\"", elementName); @@ -847,14 +850,16 @@ namespace umbraco.cms.businesslogic.template string alias = xmlHelper.GetNodeValue(n.SelectSingleNode("Alias")); Template t = Template.GetByAlias(alias); + var design = xmlHelper.GetNodeValue(n.SelectSingleNode("Design")); if (t == null) { - t = MakeNew(xmlHelper.GetNodeValue(n.SelectSingleNode("Name")), u); + //create the template with the design if one is specified + t = MakeNew(xmlHelper.GetNodeValue(n.SelectSingleNode("Name")), u, + design.IsNullOrWhiteSpace() ? null : design); } t.Alias = alias; - t.ImportDesign(xmlHelper.GetNodeValue(n.SelectSingleNode("Design"))); return t; } From 7fefde4c8a825669753f557bf85f256114f3cc00 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 10 Oct 2012 23:44:42 +0500 Subject: [PATCH 06/15] Fixes: U4-1011, YSOD is generated if any created/installed packages files exist but they are empty. --- .../businesslogic/Packager/data.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/umbraco.cms/businesslogic/Packager/data.cs b/src/umbraco.cms/businesslogic/Packager/data.cs index 8e0c5ea366..9c0241c31f 100644 --- a/src/umbraco.cms/businesslogic/Packager/data.cs +++ b/src/umbraco.cms/businesslogic/Packager/data.cs @@ -3,6 +3,7 @@ using System.Xml; using System.Xml.XPath; using System.Collections.Generic; using System.IO; +using Umbraco.Core; namespace umbraco.cms.businesslogic.packager { @@ -46,6 +47,24 @@ namespace umbraco.cms.businesslogic.packager { _source = new XmlDocument(); } + + //error checking here + if (File.Exists(dataSource)) + { + var isEmpty = false; + using (var sr = new StreamReader(dataSource)) + { + if (sr.ReadToEnd().IsNullOrWhiteSpace()) + { + isEmpty = true; + } + } + if (isEmpty) + { + File.WriteAllText(dataSource, @""); + } + } + _source.Load(dataSource); } From 8e914e751c9fc5a59352d861ab6afac4afd54f37 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 11 Oct 2012 00:46:19 +0500 Subject: [PATCH 07/15] Fixes: U4-1013 - editing a View file in template edit ensures no duplicated files. --- src/Umbraco.Core/IO/IOHelper.cs | 2 - .../umbraco/Trees/loadTemplates.cs | 6 ++- .../developer/Packages/editPackage.aspx.cs | 8 ++-- .../template/MasterpageHelper.cs | 21 ++++++---- .../businesslogic/template/Template.cs | 42 ++++++++++++------- .../businesslogic/template/ViewHelper.cs | 42 +++++++++++++++---- 6 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index 5ee613cccd..32e15d826d 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -117,7 +117,6 @@ namespace Umbraco.Core.IO } //use a tilde character instead of the complete path - [Obsolete("This method is no longer in use and will be removed in future versions")] internal static string ReturnPath(string settingsKey, string standardPath, bool useTilde) { string retval = ConfigurationManager.AppSettings[settingsKey]; @@ -128,7 +127,6 @@ namespace Umbraco.Core.IO return retval.TrimEnd('/'); } - [Obsolete("This method is no longer in use and will be removed in future versions")] internal static string ReturnPath(string settingsKey, string standardPath) { return ReturnPath(settingsKey, standardPath, false); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadTemplates.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadTemplates.cs index d8336963d2..ac18b1775f 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadTemplates.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadTemplates.cs @@ -194,12 +194,14 @@ namespace umbraco xNode.Source = GetTreeServiceUrl(t.Id); xNode.HasChildren = t.HasChildren; - if (Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine == RenderingEngine.Mvc && Template.HasView(t)) + if (Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine == RenderingEngine.Mvc && ViewHelper.ViewExists(t)) { xNode.Action = "javascript:openView(" + t.Id + ");"; xNode.Icon = "settingView.gif"; xNode.OpenIcon = "settingView.gif"; - }else{ + } + else + { xNode.Action = "javascript:openTemplate(" + t.Id + ");"; xNode.Icon = "settingTemplate.gif"; xNode.OpenIcon = "settingTemplate.gif"; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs index 5a9a9ae43c..dc57f13324 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/editPackage.aspx.cs @@ -191,10 +191,10 @@ namespace umbraco.presentation.developer.packages else { if (e.CommandName == "save") - savePackage(true); + SavePackage(true); if (e.CommandName == "publish") { - savePackage(false); + SavePackage(false); int packageID = int.Parse(Request.QueryString["id"]); //string packFileName = cms.businesslogic.packager. Publish.publishPackage(packageID); @@ -216,7 +216,7 @@ namespace umbraco.presentation.developer.packages protected void generateXML(object sender, EventArgs e) { } - private void savePackage(bool showNotification) { + private void SavePackage(bool showNotification) { pack.Author = packageAuthorName.Text; pack.AuthorUrl = packageAuthorUrl.Text; @@ -345,7 +345,7 @@ namespace umbraco.presentation.developer.packages packageFilesRepeater.DataBind(); } - private static string joinList(List list, char seperator) { + private static string JoinList(List list, char seperator) { string retVal = ""; foreach (string str in list) { retVal += str + seperator.ToString(); diff --git a/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs index 3eb450ef0d..d0d2ba12da 100644 --- a/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs +++ b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs @@ -15,18 +15,23 @@ namespace umbraco.cms.businesslogic.template internal static bool MasterPageExists(Template t) { - return File.Exists(t.MasterPageFile); + return File.Exists(GetFilePath(t)); + } + + internal static string GetFilePath(Template t) + { + return IOHelper.MapPath(SystemDirectories.Masterpages + "/" + t.Alias.Replace(" ", "") + ".master"); } internal static string CreateMasterpageFile(Template t, bool overWrite = false) { string masterpageContent = ""; - if (!File.Exists(t.MasterPageFile) || overWrite) + if (!File.Exists(GetFilePath(t)) || overWrite) masterpageContent = SaveTemplateToFile(t, t.Alias); else { - System.IO.TextReader tr = new StreamReader(t.MasterPageFile); + System.IO.TextReader tr = new StreamReader(GetFilePath(t)); masterpageContent = tr.ReadToEnd(); tr.Close(); } @@ -34,11 +39,12 @@ namespace umbraco.cms.businesslogic.template return masterpageContent; } - internal static string GetMasterpageFile(Template t) + internal static string GetFileContents(Template t) { string masterpageContent = ""; - if (File.Exists(t.MasterPageFile)){ - System.IO.TextReader tr = new StreamReader(t.MasterPageFile); + if (File.Exists(GetFilePath(t))) + { + System.IO.TextReader tr = new StreamReader(GetFilePath(t)); masterpageContent = tr.ReadToEnd(); tr.Close(); } @@ -104,7 +110,6 @@ namespace umbraco.cms.businesslogic.template //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); @@ -117,7 +122,7 @@ namespace umbraco.cms.businesslogic.template } // save the file in UTF-8 - System.IO.File.WriteAllText(template.MasterPageFile, masterPageContent, System.Text.Encoding.UTF8); + System.IO.File.WriteAllText(GetFilePath(template), masterPageContent, System.Text.Encoding.UTF8); return masterPageContent; } diff --git a/src/umbraco.cms/businesslogic/template/Template.cs b/src/umbraco.cms/businesslogic/template/Template.cs index 18f29563be..c183ab9698 100644 --- a/src/umbraco.cms/businesslogic/template/Template.cs +++ b/src/umbraco.cms/businesslogic/template/Template.cs @@ -45,11 +45,31 @@ namespace umbraco.cms.businesslogic.template #endregion + [Obsolete("Use TemplateFilePath instead")] public string MasterPageFile { - get { return IOHelper.MapPath(SystemDirectories.Masterpages + "/" + Alias.Replace(" ", "") + ".master"); } + get { return TemplateFilePath; } } + /// + /// Returns the file path for the current template + /// + public string TemplateFilePath + { + get + { + switch (DetermineRenderingEngine(this)) + { + case RenderingEngine.Mvc: + return ViewHelper.GetFilePath(this); + case RenderingEngine.WebForms: + return MasterpageHelper.GetFilePath(this); + default: + throw new ArgumentOutOfRangeException(); + } + } + } + public static Hashtable TemplateAliases { get { return _templateAliases; } @@ -134,10 +154,10 @@ namespace umbraco.cms.businesslogic.template } dr.Close(); - if (Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine == RenderingEngine.Mvc && Template.HasView(this)) - _design = ViewHelper.GetViewFile(this); + if (Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine == RenderingEngine.Mvc && ViewHelper.ViewExists(this)) + _design = ViewHelper.GetFileContents(this); else - _design = MasterpageHelper.GetMasterpageFile(this); + _design = MasterpageHelper.GetFileContents(this); } @@ -251,7 +271,7 @@ namespace umbraco.cms.businesslogic.template //we only switch to MVC View editing if the template has a view file, and MVC editing is enabled if (Umbraco.Core.Configuration.UmbracoSettings.DefaultRenderingEngine == RenderingEngine.Mvc && !MasterpageHelper.IsMasterPageSyntax(_design)) - _design = ViewHelper.UpdateViewFile(this); + _design = ViewHelper.UpdateViewFile(this, _oldAlias); else if (UmbracoSettings.UseAspNetMasterPages) _design = MasterpageHelper.UpdateMasterpageFile(this, _oldAlias); @@ -551,8 +571,8 @@ 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))); + if (System.IO.File.Exists(Umbraco.Core.IO.IOHelper.MapPath(ViewHelper.ViewPath(this.Alias)))) + System.IO.File.Delete(Umbraco.Core.IO.IOHelper.MapPath(ViewHelper.ViewPath(this.Alias))); FireAfterDelete(e); } @@ -863,13 +883,7 @@ namespace umbraco.cms.businesslogic.template 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 index aa9e34711e..82c554921b 100644 --- a/src/umbraco.cms/businesslogic/template/ViewHelper.cs +++ b/src/umbraco.cms/businesslogic/template/ViewHelper.cs @@ -11,14 +11,19 @@ namespace umbraco.cms.businesslogic.template { internal static bool ViewExists(Template t) { - string path = IOHelper.MapPath(ViewPath(t)); + string path = GetFilePath(t); return File.Exists(path); } - internal static string GetViewFile(Template t) + internal static string GetFilePath(Template t) + { + return IOHelper.MapPath(ViewPath(t.Alias)); + } + + internal static string GetFileContents(Template t) { string viewContent = ""; - string path = IOHelper.MapPath(ViewPath(t)); + string path = IOHelper.MapPath(ViewPath(t.Alias)); if (File.Exists(path)) { @@ -33,7 +38,7 @@ namespace umbraco.cms.businesslogic.template internal static string CreateViewFile(Template t, bool overWrite = false) { string viewContent = ""; - string path = IOHelper.MapPath(ViewPath(t)); + string path = IOHelper.MapPath(ViewPath(t.Alias)); if (!File.Exists(path) || overWrite) viewContent = SaveTemplateToFile(t, t.Alias); @@ -50,21 +55,40 @@ namespace umbraco.cms.businesslogic.template internal static string SaveTemplateToFile(Template template, string currentAlias) { var design = EnsureInheritedLayout(template); - System.IO.File.WriteAllText(IOHelper.MapPath(ViewPath(template)), design, Encoding.UTF8); + System.IO.File.WriteAllText(IOHelper.MapPath(ViewPath(template.Alias)), design, Encoding.UTF8); return template.Design; } - internal static string UpdateViewFile(Template t) + internal static string UpdateViewFile(Template t, string currentAlias = null) { - var path = IOHelper.MapPath(ViewPath(t)); + var path = IOHelper.MapPath(ViewPath(t.Alias)); + + if (!string.IsNullOrEmpty(currentAlias) && currentAlias != t.Alias) + { + //NOTE: I don't think this is needed for MVC, this was ported over from the + // masterpages helper but I think only relates to when templates are stored in the db. + ////Ensure that child templates have the right master masterpage file name + //if (t.HasChildren) + //{ + // var c = t.Children; + // foreach (CMSNode cmn in c) + // UpdateViewFile(new Template(cmn.Id), null); + //} + + //then kill the old file.. + var oldFile = IOHelper.MapPath(ViewPath(currentAlias)); + if (System.IO.File.Exists(oldFile)) + System.IO.File.Delete(oldFile); + } + System.IO.File.WriteAllText(path, t.Design, Encoding.UTF8); return t.Design; } - public static string ViewPath(Template t) + public static string ViewPath(string alias) { - return Umbraco.Core.IO.SystemDirectories.MvcViews + "/" + t.Alias.Replace(" ", "") + ".cshtml"; + return Umbraco.Core.IO.SystemDirectories.MvcViews + "/" + alias.Replace(" ", "") + ".cshtml"; } From ce4828d67897bc4418698aa49637502b2cad0217 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 11 Oct 2012 02:30:48 +0500 Subject: [PATCH 08/15] Fixes HasContent if there is actually no content (new install). Fixes issue with TreeDefinitionCollection not initializing when accessing singleton... not sure how i overlooked that before. This fixes issues with MNTP initialization and probably some other tree stuff. Removes warning log in umbracomodule for not a document as this just takes up space in the log. Fixes issue with logger that was logging 'Info' for our internal Debug calls. --- src/Umbraco.Core/DisposableTimer.cs | 2 +- .../LegacyTransientObjectsResolver.cs | 2 +- .../DefaultPublishedContentStore.cs | 5 +- src/Umbraco.Web/UmbracoModule.cs | 9 +- .../umbraco/Trees/TreeDefinitionCollection.cs | 1 + .../MultiNodeTreePicker/MNTP_DataEditor.cs | 1338 ++++++++--------- 6 files changed, 675 insertions(+), 682 deletions(-) diff --git a/src/Umbraco.Core/DisposableTimer.cs b/src/Umbraco.Core/DisposableTimer.cs index 5269244609..f60c3a5634 100644 --- a/src/Umbraco.Core/DisposableTimer.cs +++ b/src/Umbraco.Core/DisposableTimer.cs @@ -87,7 +87,7 @@ namespace Umbraco.Core /// public static DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage) { - LogHelper.Info(loggerType, () => startMessage); + LogHelper.Debug(loggerType, () => startMessage); return new DisposableTimer(x => LogHelper.Debug(loggerType, () => completeMessage + " (took " + x + "ms)")); } diff --git a/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs b/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs index 582ec50b9e..27f2307bd2 100644 --- a/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs +++ b/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs @@ -33,7 +33,7 @@ namespace Umbraco.Core.ObjectResolution /// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier. /// protected LegacyTransientObjectsResolver(IEnumerable refreshers) - : base(ObjectLifetimeScope.Transient) // false = new objects every time + : base(ObjectLifetimeScope.Transient) // new objects every time { foreach (var l in refreshers) { diff --git a/src/Umbraco.Web/DefaultPublishedContentStore.cs b/src/Umbraco.Web/DefaultPublishedContentStore.cs index c1d79283a7..1b8dfddc7c 100644 --- a/src/Umbraco.Web/DefaultPublishedContentStore.cs +++ b/src/Umbraco.Web/DefaultPublishedContentStore.cs @@ -161,7 +161,10 @@ namespace Umbraco.Web public bool HasContent(UmbracoContext umbracoContext) { - var node = GetXml(umbracoContext).SelectSingleNode(XPathStrings.RootDocuments); + var xml = GetXml(umbracoContext); + if (xml == null) + return false; + var node = xml.SelectSingleNode(XPathStrings.RootDocuments); return node != null; } diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 5f84c387f6..8368563990 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -271,10 +271,11 @@ namespace Umbraco.Web if (maybeDoc && GlobalSettings.IsReservedPathOrUrl(lpath)) maybeDoc = false; - if (!maybeDoc) - { - LogHelper.Warn("Not a document"); - } + //NOTE: No need to warn, plus if we do we should log the document, as this message doesn't really tell us anything :) + //if (!maybeDoc) + //{ + // LogHelper.Warn("Not a document"); + //} return maybeDoc; } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs index e8aca83c1a..5d816ce07f 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs @@ -33,6 +33,7 @@ namespace umbraco.cms.presentation.Trees { get { + instance.EnsureTreesRegistered(); return instance; } } diff --git a/src/umbraco.editorControls/MultiNodeTreePicker/MNTP_DataEditor.cs b/src/umbraco.editorControls/MultiNodeTreePicker/MNTP_DataEditor.cs index a36b93e5f9..6e0a04320b 100644 --- a/src/umbraco.editorControls/MultiNodeTreePicker/MNTP_DataEditor.cs +++ b/src/umbraco.editorControls/MultiNodeTreePicker/MNTP_DataEditor.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Web; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Xml.Linq; using ClientDependency.Core; +using Umbraco.Core; using umbraco.cms.presentation.Trees; using umbraco.controls.Images; using umbraco.controls.Tree; @@ -17,679 +19,665 @@ using umbraco.IO; namespace umbraco.editorControls.MultiNodeTreePicker { - /// - /// The user interface to display to the content editor - /// - [ClientDependency(ClientDependencyType.Javascript, "ui/jqueryui.js", "UmbracoClient")] - [ClientDependency(ClientDependencyType.Javascript, "ui/jquery.tooltip.min.js", "UmbracoClient")] - [ClientDependency(ClientDependencyType.Javascript, "controls/Images/ImageViewer.js", "UmbracoRoot")] - public class MNTP_DataEditor : Control, INamingContainer - { - #region Static Constructor - - /// - /// This adds our filtered tree definition to the TreeDefinitionCollection at runtime - /// instead of having to declare it in the database - /// - static MNTP_DataEditor() - { - if (TreeDefinitionCollection.Instance - .Where(x => x.TreeType == typeof(FilteredContentTree)) - .Count() == 0) - { - lock (m_Locker) - { - //double check lock.... - - if (TreeDefinitionCollection.Instance - .Where(x => x.TreeType == typeof(FilteredContentTree)) - .Count() == 0) - { - //need to add our tree definitions to the collection. - - //find the content tree to duplicate - var contentTree = TreeDefinitionCollection.Instance.Where(x => x.Tree.Alias.ToUpper() == "CONTENT").Single(); - var filteredContentTree = new TreeDefinition(typeof(FilteredContentTree), - new umbraco.BusinessLogic.ApplicationTree(true, false, 0, - contentTree.Tree.ApplicationAlias, - "FilteredContentTree", - contentTree.Tree.Title, - contentTree.Tree.IconClosed, - contentTree.Tree.IconOpened, - "umbraco.editorControls", - "MultiNodeTreePicker.FilteredContentTree", - contentTree.Tree.Action), - contentTree.App); - - //find the media tree to duplicate - var mediaTree = TreeDefinitionCollection.Instance.Where(x => x.Tree.Alias.ToUpper() == "MEDIA").Single(); - var filteredMediaTree = new TreeDefinition(typeof(FilteredMediaTree), - new umbraco.BusinessLogic.ApplicationTree(true, false, 0, - mediaTree.Tree.ApplicationAlias, - "FilteredMediaTree", - contentTree.Tree.Title, - contentTree.Tree.IconClosed, - contentTree.Tree.IconOpened, - "umbraco.editorControls", - "MultiNodeTreePicker.FilteredMediaTree", - contentTree.Tree.Action), - contentTree.App); - - //add it to the collection at runtime - TreeDefinitionCollection.Instance.Add(filteredContentTree); - TreeDefinitionCollection.Instance.Add(filteredMediaTree); - } - } - } - } - - #endregion - - /// - /// Initializes a new instance of the class. - /// - public MNTP_DataEditor() - { - this.MediaTypesWithThumbnails = new string[] { "image" }; - ShowThumbnailsForMedia = true; - TreeToRender = "content"; - MaxNodeCount = -1; - MinNodeCount = 0; - StartNodeId = uQuery.RootNodeId; - ShowToolTips = true; - ControlHeight = 200; - } - - #region Static members - /// - /// Used for locking code blocks - /// - private static readonly object m_Locker = new object(); - #endregion - - #region Protected members - - /// - /// - /// - protected CustomValidator MinItemsValidator; - - /// - /// - /// - protected CustomTreeControl TreePickerControl; - - /// - /// - /// - protected Repeater SelectedValues; - - /// - /// - /// - protected HiddenField PickedValue; - - /// - /// - /// - protected HtmlGenericControl RightColumn; - #endregion - - #region public Properties - - /// - /// gets/sets the value based on an array of IDs selected - /// - public string[] SelectedIds - { - get - { - List val = new List(); - var splitVals = PickedValue.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - //this will make sure only the node count specified is saved - //into umbraco, even if people try to hack the front end for whatever reason. - if (MaxNodeCount >= 0) - { - for (var i = 0; i < splitVals.Length; i++) - { - if (i < MaxNodeCount) - { - val.Add(splitVals[i]); - } - else break; - } - } - else - { - val = splitVals.ToList(); - } - return val.ToArray(); - } - set - { - XmlValue = ConvertToXDocument(value); - } - } - - /// - /// get/set the value for the selected nodes in xml format - /// - public XDocument XmlValue - { - get - { - return ConvertToXDocument(SelectedIds); - } - set - { - if (value == null) - { - SelectedValues.DataSource = null; - PickedValue.Value = ""; - } - else - { - //set the data source for the repeater and hidden field - var nodes = value.Descendants("nodeId"); - SelectedValues.DataSource = nodes; - PickedValue.Value = string.Join(",", nodes.Select(x => x.Value).ToArray()); - } - } - } - - /// - /// The property name being edited with the current data editor. This is used for the min items validation statement. - /// - public string PropertyName { get; set; } - - /// - /// The tree type alias to render - /// - public string TreeToRender { get; set; } - - /// - /// An xpath filter to match nodes that will be disabled from being clicked - /// - public string XPathFilter { get; set; } - - /// - /// The minimum amount of nodes that can be selected - /// - public int MinNodeCount { get; set; } - - /// - /// The maximum amount of nodes that can be selected - /// - public int MaxNodeCount { get; set; } - - /// - /// The start node id - /// - public int StartNodeId { get; set; } - - /// - /// The start node selection type - /// - public NodeSelectionType StartNodeSelectionType { get; set; } - - /// - /// The xpath expression type to select the start node when the StartNodeSelectionType is XPath - /// - public XPathExpressionType StartNodeXPathExpressionType { get; set; } - - /// - /// The XPath expression to use to determine the start node when the StartNodeSelectionType is XPath - /// - public string StartNodeXPathExpression { get; set; } - - /// - /// Gets or sets a value indicating whether [show tool tips]. - /// - /// true if [show tool tips]; otherwise, false. - /// Shows/Hides the tooltip info bubble. - public bool ShowToolTips { get; set; } - - /// - /// The XPathFilterType to match - /// - public XPathFilterType XPathFilterMatchType { get; set; } - - /// - /// Gets or sets a value indicating whether [show thumbnails for media]. - /// - /// - /// true if [show thumbnails for media]; otherwise, false. - /// - /// Whether or not to show thumbnails for media - public bool ShowThumbnailsForMedia { get; set; } - - /// - /// A list of media type names that can have thumbnails (i.e. 'image') - /// - public string[] MediaTypesWithThumbnails { get; set; } - - /// - /// This is set by the data type and allows us to save a cookie value - /// for persistence for the data type. - /// - public int DataTypeDefinitionId { get; set; } - - /// - /// The height of the tree control box in pixels - /// - public int ControlHeight { get; set; } - - #endregion - - /// - /// Initialize the control, make sure children are created - /// - /// An object that contains the event data. - protected override void OnInit(EventArgs e) - { - base.OnInit(e); - - EnsureChildControls(); - } - - /// - /// Add the resources (sytles/scripts) - /// - /// - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); - - //add the js/css required - this.RegisterEmbeddedClientResource("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerStyles.css", umbraco.cms.businesslogic.datatype.ClientDependencyType.Css); - this.RegisterEmbeddedClientResource("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerScripts.js", umbraco.cms.businesslogic.datatype.ClientDependencyType.Javascript); - - //update the tree type (we need to do this each time because i don't think view state works with these controls) - switch (TreeToRender) - { - case "media": - TreePickerControl.TreeType = "FilteredMediaTree"; - TreePickerControl.App = "media"; - break; - case "content": - default: - TreePickerControl.TreeType = "FilteredContentTree"; - TreePickerControl.App = "content"; - break; - } - - if (Page.IsPostBack) - { - //since it is a post back, bind the data source to the view state values - XmlValue = ConvertToXDocument(SelectedIds); - } - - //bind the repeater if theres a data source, or if there's no datasource but this is a postback (i.e. nodes deleted) - if (SelectedValues.DataSource != null || Page.IsPostBack) - { - SelectedValues.DataBind(); - } - - } - - /// - /// Creates the child controls for this control - /// - protected override void CreateChildControls() - { - base.CreateChildControls(); - - EnsureChildControls(); - - //create the tree control - TreePickerControl = new CustomTreeControl - { - ID = "TreePicker", - IsDialog = true, - ShowContextMenu = false, - DialogMode = TreeDialogModes.id, - Height = Unit.Pixel(ControlHeight), - StartNodeID = StartNodeId - }; - - //create the hidden field - PickedValue = new HiddenField { ID = "PickedValue" }; - - //create the right column - RightColumn = new HtmlGenericControl("div") { ID = "RightColumn" }; - RightColumn.Attributes.Add("class", "right propertypane"); - - //create the repeater - SelectedValues = new Repeater - { - //EnableViewState = false, - ID = "SelectedValues", - ItemTemplate = new SelectedItemsTemplate() - }; - - SelectedValues.ItemDataBound += SelectedValues_ItemDataBound; - - //add the repeater to the right column - RightColumn.Controls.Add(SelectedValues); - - MinItemsValidator = new CustomValidator() - { - ID = "MinItemsValidator", - ErrorMessage = - string.Format(MNTPResources.Val_MinItemsInvalid, MinNodeCount) - }; - MinItemsValidator.ServerValidate += new ServerValidateEventHandler(MinItemsValidator_ServerValidate); - - //add the controls - this.Controls.Add(MinItemsValidator); - this.Controls.Add(TreePickerControl); - this.Controls.Add(PickedValue); - this.Controls.Add(RightColumn); - } - - - - /// - /// Ensure the repeater is data bound - /// - public override void DataBind() - { - base.DataBind(); - SelectedValues.DataBind(); - } - - void MinItemsValidator_ServerValidate(object source, ServerValidateEventArgs args) - { - args.IsValid = true; - if (MinNodeCount > 0 && SelectedIds.Length < MinNodeCount) - { - args.IsValid = false; - } - } - - /// - /// Event handler for the selected node repeater. - /// This will fill in all of the text values, icons, etc.. for nodes based on their ID. - /// - /// - /// - void SelectedValues_ItemDataBound(object sender, RepeaterItemEventArgs e) - { - var liSelectNode = (HtmlGenericControl)e.Item.FindControl("SelectedNodeListItem"); - var lnkSelectNode = (HtmlAnchor)e.Item.FindControl("SelectedNodeLink"); - var litSelectNodeName = (Literal)e.Item.FindControl("SelectedNodeText"); - var infoButton = (HtmlAnchor)e.Item.FindControl("InfoButton"); - - //hide the info button if tooltips are hidden - if (!ShowToolTips) - { - infoButton.Style.Add(HtmlTextWriterStyle.Display, "none"); - } - - var thisNode = (XElement)e.Item.DataItem; - int thisNodeId; - if (int.TryParse(thisNode.Value, out thisNodeId)) - { - umbraco.cms.businesslogic.Content loadedNode; - - try - { - loadedNode = new umbraco.cms.businesslogic.Content(thisNodeId); - - //add the node id - liSelectNode.Attributes["rel"] = thisNodeId.ToString(); - //add the path to be referenced - liSelectNode.Attributes["umb:nodedata"] = loadedNode.Path; - lnkSelectNode.HRef = "javascript:void(0);"; - litSelectNodeName.Text = loadedNode.Text; - - if (loadedNode.IsTrashed) - { - //need to flag this to be removed which will be done after all items are data bound - liSelectNode.Attributes["rel"] = "trashed"; - } - else - { - //we need to set the icon - if (loadedNode.ContentTypeIcon.StartsWith(".spr")) - lnkSelectNode.Attributes["class"] += " " + loadedNode.ContentTypeIcon.TrimStart('.'); - else - { - //it's a real icon, so make it a background image - lnkSelectNode.Style.Add(HtmlTextWriterStyle.BackgroundImage, - string.Format("url('{0}')", IconPath + loadedNode.ContentTypeIcon)); - //set the nospr class since it's not a sprite - lnkSelectNode.Attributes["class"] += " noSpr"; - } - - //show the media preview if media and allowed - if (TreeToRender == "media" && ShowThumbnailsForMedia) - { - var imgPreview = (ImageViewer)e.Item.FindControl("ImgPreview"); - //show the thubmnail controls - imgPreview.Visible = true; - - //add the item class - var item = (HtmlGenericControl)e.Item.FindControl("Item"); - item.Attributes["class"] += " thumb-item"; - - //item.Style.Add(HtmlTextWriterStyle.Height, "50px"); - ////make the content sit beside the item - //var inner = (HtmlGenericControl)e.Item.FindControl("InnerItem"); - //inner.Style.Add(HtmlTextWriterStyle.Width, "224px"); - - //check if it's a thumbnail type element, we need to check both schemas - if (MediaTypesWithThumbnails.Select(x => x.ToUpper()) - .Contains(loadedNode.ContentType.Alias.ToUpper())) - { - imgPreview.MediaId = thisNodeId; - imgPreview.DataBind(); - } - } - } - - } - catch (ArgumentException) - { - //the node no longer exists, so we display a msg - litSelectNodeName.Text = "NODE NO LONGER EXISTS"; - } - } - } - - /// - /// set the nodekey to the id of this datatype - /// - /// - /// this is how get the xpath out of the cookie to know how the tree knows how to filter things. - /// generally the nodekey is used for a string id, but we'll use it for something different. - /// - /// - protected override void OnPreRender(EventArgs e) - { - base.OnPreRender(e); - - TreePickerControl.NodeKey = this.DataTypeDefinitionId.ToString(); - - SavePersistentValuesForTree(XPathFilter); - } - - /// - /// Override render to control the exact output of what is rendered this includes instantiating the jquery plugin - /// - /// The object that receives the server control content. - /// - /// Generally i don't like to do this but there's a few div's, etc... to render so this makes more sense. - /// - protected override void Render(HtmlTextWriter writer) - { - //
    - //
    - //
    Select items
    - //
    - //
    - // - //
    - //
    - //
    - //
    - - RenderTooltip(writer); - - writer.AddAttribute("class", (!MinItemsValidator.IsValid ? "error " : "") + "multiNodePicker clearfix"); - writer.AddAttribute("id", this.ClientID); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - - writer.AddAttribute("class", "header propertypane"); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - writer.Write("Select Items"); - writer.RenderEndTag(); - writer.RenderEndTag(); - - writer.AddAttribute("class", "left propertypane"); - writer.AddStyleAttribute(HtmlTextWriterStyle.Height, ((ControlHeight + 10).ToString() + "px")); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - //add the tree control here - TreePickerControl.RenderControl(writer); - writer.RenderEndTag(); - - RightColumn.RenderControl(writer); - - //render the hidden field - PickedValue.RenderControl(writer); - - writer.RenderEndTag(); //end multiNodePicker div - - var tooltipAjaxUrl = IOHelper.ResolveUrl(SystemDirectories.Umbraco) + @"/controls/Tree/CustomTreeService.asmx/GetNodeInfo"; - - //add jquery window load event to create the js tree picker - var jsMethod = string.Format("jQuery('#{0}').MultiNodeTreePicker('{1}', {2}, '{3}', {4}, {5}, '{6}', '{7}');", - TreePickerControl.ClientID, - this.ClientID, - MaxNodeCount, - tooltipAjaxUrl, - ShowToolTips.ToString().ToLower(), - (TreeToRender == "media" && ShowThumbnailsForMedia).ToString().ToLower(), - IOHelper.ResolveUrl(SystemDirectories.Umbraco), - TreeToRender); - var js = "jQuery(window).load(function() { " + jsMethod + " });"; - - writer.WriteLine(""); - - } - - /// - /// converts a list of Ids to the XDocument structure - /// - /// The value. - /// - private XDocument ConvertToXDocument(IEnumerable val) - { - if (val.Count() > 0) - { - return new XDocument(new XElement("MultiNodePicker", - new XAttribute("type", TreeToRender), - val.Select(x => new XElement("nodeId", x.ToString())))); - } - else - { - //return null to support recursive values - return null; - - //return an empty node set - //return new XDocument(new XElement("MultiNodePicker")); - } - } - - /// - /// this will render the tooltip object on the page so long as another - /// one hasn't already been registered. There should only be one tooltip. - /// - private void RenderTooltip(HtmlTextWriter writer) - { - if (this.Page.Items.Contains("MNTPTooltip")) - { - return; - } - - //render the tooltip holder - //
    - //
    - //
    - //
    - //this.Page.Controls.AddAt(0, new LiteralControl("
    ")); - writer.AddAttribute("id", "MNTPTooltip"); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - writer.AddAttribute("class", "throbber"); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - writer.RenderEndTag(); //end throbber - writer.AddAttribute("class", "tooltipInfo"); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - writer.RenderEndTag(); //end tooltipInfo - writer.RenderEndTag(); //end tooltipo - - //ensure we add this to our page items so it's not duplicated - this.Page.Items.Add("MNTPTooltip", true); - } - - /// - /// This will update the multi-node tree picker data which is used to store - /// the xpath data and xpath match type for this control id. - /// - /// The xpath. - /// - /// This will save the data into a cookie and also into the request cookie. It must save - /// it to both locations in case the request cookie has been changed and the request cookie - /// is different than the response cookie. - /// - private void SavePersistentValuesForTree(string xpath) - { - - //create the output cookie with all of the values of the request cookie - - var newCookie = HttpContext.Current.Response.Cookies[MNTP_DataType.PersistenceCookieName] ?? new HttpCookie(MNTP_DataType.PersistenceCookieName); - - //store the xpath for this data type definition - newCookie.MntpAddXPathFilter(this.DataTypeDefinitionId, xpath); - //store the match type - newCookie.MntpAddXPathFilterType(this.DataTypeDefinitionId, XPathFilterMatchType); - //store the start node id - newCookie.MntpAddStartNodeId(this.DataTypeDefinitionId, StartNodeId); - //store the start node selection type - newCookie.MntpAddStartNodeSelectionType(this.DataTypeDefinitionId, StartNodeSelectionType); - //store the start node xpath expression type - newCookie.MntpAddStartNodeXPathExpressionType(this.DataTypeDefinitionId, StartNodeXPathExpressionType); - //store the start node xpath expression - newCookie.MntpAddStartNodeXPathExpression(this.DataTypeDefinitionId, StartNodeXPathExpression); - //store the current editing node if found - if (!string.IsNullOrEmpty(HttpContext.Current.Request["id"])) - { - var id = 0; - if (int.TryParse(HttpContext.Current.Request["id"], out id)) - { - newCookie.MntpAddCurrentEditingNode(this.DataTypeDefinitionId, id); - } - } - - HttpContext.Current.Response.Cookies.Add(newCookie); - - //add it to the request cookies too, thus overriding any old data - if (HttpContext.Current.Request.Cookies[MNTP_DataType.PersistenceCookieName] != null && HttpContext.Current.Request.Cookies[MNTP_DataType.PersistenceCookieName].Values.Count > 0) - { - //remove the incoming one and replace with new one - HttpContext.Current.Request.Cookies.Remove(MNTP_DataType.PersistenceCookieName); - } - HttpContext.Current.Request.Cookies.Add(newCookie); - - } - - /// - /// A reference path to where the icons are actually stored as compared to where the tree themes folder is - /// - private static readonly string IconPath = IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/images/umbraco/"; - } + /// + /// The user interface to display to the content editor + /// + [ClientDependency(ClientDependencyType.Javascript, "ui/jqueryui.js", "UmbracoClient")] + [ClientDependency(ClientDependencyType.Javascript, "ui/jquery.tooltip.min.js", "UmbracoClient")] + [ClientDependency(ClientDependencyType.Javascript, "controls/Images/ImageViewer.js", "UmbracoRoot")] + public class MNTP_DataEditor : Control, INamingContainer + { + #region Static Constructor + + /// + /// This adds our filtered tree definition to the TreeDefinitionCollection at runtime + /// instead of having to declare it in the database + /// + static MNTP_DataEditor() + { + //NOTE: Before we had locking here but static ctors are always threadsafe + + if (TreeDefinitionCollection.Instance.Any(x => x.TreeType == typeof (FilteredContentTree))) + return; + + + //need to add our tree definitions to the collection. + + //find the content tree to duplicate + var contentTree = TreeDefinitionCollection.Instance.Single(x => x.Tree.Alias.ToUpper() == "CONTENT"); + var filteredContentTree = new TreeDefinition(typeof(FilteredContentTree), + new umbraco.BusinessLogic.ApplicationTree(true, false, 0, + contentTree.Tree.ApplicationAlias, + "FilteredContentTree", + contentTree.Tree.Title, + contentTree.Tree.IconClosed, + contentTree.Tree.IconOpened, + "umbraco.editorControls", + "MultiNodeTreePicker.FilteredContentTree", + contentTree.Tree.Action), + contentTree.App); + + //find the media tree to duplicate + var mediaTree = TreeDefinitionCollection.Instance.Single(x => x.Tree.Alias.ToUpper() == "MEDIA"); + var filteredMediaTree = new TreeDefinition(typeof(FilteredMediaTree), + new umbraco.BusinessLogic.ApplicationTree(true, false, 0, + mediaTree.Tree.ApplicationAlias, + "FilteredMediaTree", + contentTree.Tree.Title, + contentTree.Tree.IconClosed, + contentTree.Tree.IconOpened, + "umbraco.editorControls", + "MultiNodeTreePicker.FilteredMediaTree", + contentTree.Tree.Action), + contentTree.App); + + //add it to the collection at runtime + TreeDefinitionCollection.Instance.Add(filteredContentTree); + TreeDefinitionCollection.Instance.Add(filteredMediaTree); + } + + #endregion + + /// + /// Initializes a new instance of the class. + /// + public MNTP_DataEditor() + { + this.MediaTypesWithThumbnails = new string[] { "image" }; + ShowThumbnailsForMedia = true; + TreeToRender = "content"; + MaxNodeCount = -1; + MinNodeCount = 0; + StartNodeId = uQuery.RootNodeId; + ShowToolTips = true; + ControlHeight = 200; + } + + + + #region Protected members + + /// + /// + /// + protected CustomValidator MinItemsValidator; + + /// + /// + /// + protected CustomTreeControl TreePickerControl; + + /// + /// + /// + protected Repeater SelectedValues; + + /// + /// + /// + protected HiddenField PickedValue; + + /// + /// + /// + protected HtmlGenericControl RightColumn; + #endregion + + #region public Properties + + /// + /// gets/sets the value based on an array of IDs selected + /// + public string[] SelectedIds + { + get + { + List val = new List(); + var splitVals = PickedValue.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + //this will make sure only the node count specified is saved + //into umbraco, even if people try to hack the front end for whatever reason. + if (MaxNodeCount >= 0) + { + for (var i = 0; i < splitVals.Length; i++) + { + if (i < MaxNodeCount) + { + val.Add(splitVals[i]); + } + else break; + } + } + else + { + val = splitVals.ToList(); + } + return val.ToArray(); + } + set + { + XmlValue = ConvertToXDocument(value); + } + } + + /// + /// get/set the value for the selected nodes in xml format + /// + public XDocument XmlValue + { + get + { + return ConvertToXDocument(SelectedIds); + } + set + { + if (value == null) + { + SelectedValues.DataSource = null; + PickedValue.Value = ""; + } + else + { + //set the data source for the repeater and hidden field + var nodes = value.Descendants("nodeId"); + SelectedValues.DataSource = nodes; + PickedValue.Value = string.Join(",", nodes.Select(x => x.Value).ToArray()); + } + } + } + + /// + /// The property name being edited with the current data editor. This is used for the min items validation statement. + /// + public string PropertyName { get; set; } + + /// + /// The tree type alias to render + /// + public string TreeToRender { get; set; } + + /// + /// An xpath filter to match nodes that will be disabled from being clicked + /// + public string XPathFilter { get; set; } + + /// + /// The minimum amount of nodes that can be selected + /// + public int MinNodeCount { get; set; } + + /// + /// The maximum amount of nodes that can be selected + /// + public int MaxNodeCount { get; set; } + + /// + /// The start node id + /// + public int StartNodeId { get; set; } + + /// + /// The start node selection type + /// + public NodeSelectionType StartNodeSelectionType { get; set; } + + /// + /// The xpath expression type to select the start node when the StartNodeSelectionType is XPath + /// + public XPathExpressionType StartNodeXPathExpressionType { get; set; } + + /// + /// The XPath expression to use to determine the start node when the StartNodeSelectionType is XPath + /// + public string StartNodeXPathExpression { get; set; } + + /// + /// Gets or sets a value indicating whether [show tool tips]. + /// + /// true if [show tool tips]; otherwise, false. + /// Shows/Hides the tooltip info bubble. + public bool ShowToolTips { get; set; } + + /// + /// The XPathFilterType to match + /// + public XPathFilterType XPathFilterMatchType { get; set; } + + /// + /// Gets or sets a value indicating whether [show thumbnails for media]. + /// + /// + /// true if [show thumbnails for media]; otherwise, false. + /// + /// Whether or not to show thumbnails for media + public bool ShowThumbnailsForMedia { get; set; } + + /// + /// A list of media type names that can have thumbnails (i.e. 'image') + /// + public string[] MediaTypesWithThumbnails { get; set; } + + /// + /// This is set by the data type and allows us to save a cookie value + /// for persistence for the data type. + /// + public int DataTypeDefinitionId { get; set; } + + /// + /// The height of the tree control box in pixels + /// + public int ControlHeight { get; set; } + + #endregion + + /// + /// Initialize the control, make sure children are created + /// + /// An object that contains the event data. + protected override void OnInit(EventArgs e) + { + base.OnInit(e); + + EnsureChildControls(); + } + + /// + /// Add the resources (sytles/scripts) + /// + /// + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + + //add the js/css required + this.RegisterEmbeddedClientResource("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerStyles.css", umbraco.cms.businesslogic.datatype.ClientDependencyType.Css); + this.RegisterEmbeddedClientResource("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerScripts.js", umbraco.cms.businesslogic.datatype.ClientDependencyType.Javascript); + + //update the tree type (we need to do this each time because i don't think view state works with these controls) + switch (TreeToRender) + { + case "media": + TreePickerControl.TreeType = "FilteredMediaTree"; + TreePickerControl.App = "media"; + break; + case "content": + default: + TreePickerControl.TreeType = "FilteredContentTree"; + TreePickerControl.App = "content"; + break; + } + + if (Page.IsPostBack) + { + //since it is a post back, bind the data source to the view state values + XmlValue = ConvertToXDocument(SelectedIds); + } + + //bind the repeater if theres a data source, or if there's no datasource but this is a postback (i.e. nodes deleted) + if (SelectedValues.DataSource != null || Page.IsPostBack) + { + SelectedValues.DataBind(); + } + + } + + /// + /// Creates the child controls for this control + /// + protected override void CreateChildControls() + { + base.CreateChildControls(); + + EnsureChildControls(); + + //create the tree control + TreePickerControl = new CustomTreeControl + { + ID = "TreePicker", + IsDialog = true, + ShowContextMenu = false, + DialogMode = TreeDialogModes.id, + Height = Unit.Pixel(ControlHeight), + StartNodeID = StartNodeId + }; + + //create the hidden field + PickedValue = new HiddenField { ID = "PickedValue" }; + + //create the right column + RightColumn = new HtmlGenericControl("div") { ID = "RightColumn" }; + RightColumn.Attributes.Add("class", "right propertypane"); + + //create the repeater + SelectedValues = new Repeater + { + //EnableViewState = false, + ID = "SelectedValues", + ItemTemplate = new SelectedItemsTemplate() + }; + + SelectedValues.ItemDataBound += SelectedValues_ItemDataBound; + + //add the repeater to the right column + RightColumn.Controls.Add(SelectedValues); + + MinItemsValidator = new CustomValidator() + { + ID = "MinItemsValidator", + ErrorMessage = + string.Format(MNTPResources.Val_MinItemsInvalid, MinNodeCount) + }; + MinItemsValidator.ServerValidate += new ServerValidateEventHandler(MinItemsValidator_ServerValidate); + + //add the controls + this.Controls.Add(MinItemsValidator); + this.Controls.Add(TreePickerControl); + this.Controls.Add(PickedValue); + this.Controls.Add(RightColumn); + } + + + + /// + /// Ensure the repeater is data bound + /// + public override void DataBind() + { + base.DataBind(); + SelectedValues.DataBind(); + } + + void MinItemsValidator_ServerValidate(object source, ServerValidateEventArgs args) + { + args.IsValid = true; + if (MinNodeCount > 0 && SelectedIds.Length < MinNodeCount) + { + args.IsValid = false; + } + } + + /// + /// Event handler for the selected node repeater. + /// This will fill in all of the text values, icons, etc.. for nodes based on their ID. + /// + /// + /// + void SelectedValues_ItemDataBound(object sender, RepeaterItemEventArgs e) + { + var liSelectNode = (HtmlGenericControl)e.Item.FindControl("SelectedNodeListItem"); + var lnkSelectNode = (HtmlAnchor)e.Item.FindControl("SelectedNodeLink"); + var litSelectNodeName = (Literal)e.Item.FindControl("SelectedNodeText"); + var infoButton = (HtmlAnchor)e.Item.FindControl("InfoButton"); + + //hide the info button if tooltips are hidden + if (!ShowToolTips) + { + infoButton.Style.Add(HtmlTextWriterStyle.Display, "none"); + } + + var thisNode = (XElement)e.Item.DataItem; + int thisNodeId; + if (int.TryParse(thisNode.Value, out thisNodeId)) + { + umbraco.cms.businesslogic.Content loadedNode; + + try + { + loadedNode = new umbraco.cms.businesslogic.Content(thisNodeId); + + //add the node id + liSelectNode.Attributes["rel"] = thisNodeId.ToString(); + //add the path to be referenced + liSelectNode.Attributes["umb:nodedata"] = loadedNode.Path; + lnkSelectNode.HRef = "javascript:void(0);"; + litSelectNodeName.Text = loadedNode.Text; + + if (loadedNode.IsTrashed) + { + //need to flag this to be removed which will be done after all items are data bound + liSelectNode.Attributes["rel"] = "trashed"; + } + else + { + //we need to set the icon + if (loadedNode.ContentTypeIcon.StartsWith(".spr")) + lnkSelectNode.Attributes["class"] += " " + loadedNode.ContentTypeIcon.TrimStart('.'); + else + { + //it's a real icon, so make it a background image + lnkSelectNode.Style.Add(HtmlTextWriterStyle.BackgroundImage, + string.Format("url('{0}')", IconPath + loadedNode.ContentTypeIcon)); + //set the nospr class since it's not a sprite + lnkSelectNode.Attributes["class"] += " noSpr"; + } + + //show the media preview if media and allowed + if (TreeToRender == "media" && ShowThumbnailsForMedia) + { + var imgPreview = (ImageViewer)e.Item.FindControl("ImgPreview"); + //show the thubmnail controls + imgPreview.Visible = true; + + //add the item class + var item = (HtmlGenericControl)e.Item.FindControl("Item"); + item.Attributes["class"] += " thumb-item"; + + //item.Style.Add(HtmlTextWriterStyle.Height, "50px"); + ////make the content sit beside the item + //var inner = (HtmlGenericControl)e.Item.FindControl("InnerItem"); + //inner.Style.Add(HtmlTextWriterStyle.Width, "224px"); + + //check if it's a thumbnail type element, we need to check both schemas + if (MediaTypesWithThumbnails.Select(x => x.ToUpper()) + .Contains(loadedNode.ContentType.Alias.ToUpper())) + { + imgPreview.MediaId = thisNodeId; + imgPreview.DataBind(); + } + } + } + + } + catch (ArgumentException) + { + //the node no longer exists, so we display a msg + litSelectNodeName.Text = "NODE NO LONGER EXISTS"; + } + } + } + + /// + /// set the nodekey to the id of this datatype + /// + /// + /// this is how get the xpath out of the cookie to know how the tree knows how to filter things. + /// generally the nodekey is used for a string id, but we'll use it for something different. + /// + /// + protected override void OnPreRender(EventArgs e) + { + base.OnPreRender(e); + + TreePickerControl.NodeKey = this.DataTypeDefinitionId.ToString(); + + SavePersistentValuesForTree(XPathFilter); + } + + /// + /// Override render to control the exact output of what is rendered this includes instantiating the jquery plugin + /// + /// The object that receives the server control content. + /// + /// Generally i don't like to do this but there's a few div's, etc... to render so this makes more sense. + /// + protected override void Render(HtmlTextWriter writer) + { + //
    + //
    + //
    Select items
    + //
    + //
    + // + //
    + //
    + //
    + //
    + + RenderTooltip(writer); + + writer.AddAttribute("class", (!MinItemsValidator.IsValid ? "error " : "") + "multiNodePicker clearfix"); + writer.AddAttribute("id", this.ClientID); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + + writer.AddAttribute("class", "header propertypane"); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + writer.Write("Select Items"); + writer.RenderEndTag(); + writer.RenderEndTag(); + + writer.AddAttribute("class", "left propertypane"); + writer.AddStyleAttribute(HtmlTextWriterStyle.Height, ((ControlHeight + 10).ToString() + "px")); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + //add the tree control here + TreePickerControl.RenderControl(writer); + writer.RenderEndTag(); + + RightColumn.RenderControl(writer); + + //render the hidden field + PickedValue.RenderControl(writer); + + writer.RenderEndTag(); //end multiNodePicker div + + var tooltipAjaxUrl = IOHelper.ResolveUrl(SystemDirectories.Umbraco) + @"/controls/Tree/CustomTreeService.asmx/GetNodeInfo"; + + //add jquery window load event to create the js tree picker + var jsMethod = string.Format("jQuery('#{0}').MultiNodeTreePicker('{1}', {2}, '{3}', {4}, {5}, '{6}', '{7}');", + TreePickerControl.ClientID, + this.ClientID, + MaxNodeCount, + tooltipAjaxUrl, + ShowToolTips.ToString().ToLower(), + (TreeToRender == "media" && ShowThumbnailsForMedia).ToString().ToLower(), + IOHelper.ResolveUrl(SystemDirectories.Umbraco), + TreeToRender); + var js = "jQuery(window).load(function() { " + jsMethod + " });"; + + writer.WriteLine(""); + + } + + /// + /// converts a list of Ids to the XDocument structure + /// + /// The value. + /// + private XDocument ConvertToXDocument(IEnumerable val) + { + if (val.Count() > 0) + { + return new XDocument(new XElement("MultiNodePicker", + new XAttribute("type", TreeToRender), + val.Select(x => new XElement("nodeId", x.ToString())))); + } + else + { + //return null to support recursive values + return null; + + //return an empty node set + //return new XDocument(new XElement("MultiNodePicker")); + } + } + + /// + /// this will render the tooltip object on the page so long as another + /// one hasn't already been registered. There should only be one tooltip. + /// + private void RenderTooltip(HtmlTextWriter writer) + { + if (this.Page.Items.Contains("MNTPTooltip")) + { + return; + } + + //render the tooltip holder + //
    + //
    + //
    + //
    + //this.Page.Controls.AddAt(0, new LiteralControl("
    ")); + writer.AddAttribute("id", "MNTPTooltip"); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + writer.AddAttribute("class", "throbber"); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + writer.RenderEndTag(); //end throbber + writer.AddAttribute("class", "tooltipInfo"); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + writer.RenderEndTag(); //end tooltipInfo + writer.RenderEndTag(); //end tooltipo + + //ensure we add this to our page items so it's not duplicated + this.Page.Items.Add("MNTPTooltip", true); + } + + /// + /// This will update the multi-node tree picker data which is used to store + /// the xpath data and xpath match type for this control id. + /// + /// The xpath. + /// + /// This will save the data into a cookie and also into the request cookie. It must save + /// it to both locations in case the request cookie has been changed and the request cookie + /// is different than the response cookie. + /// + private void SavePersistentValuesForTree(string xpath) + { + + //create the output cookie with all of the values of the request cookie + + var newCookie = HttpContext.Current.Response.Cookies[MNTP_DataType.PersistenceCookieName] ?? new HttpCookie(MNTP_DataType.PersistenceCookieName); + + //store the xpath for this data type definition + newCookie.MntpAddXPathFilter(this.DataTypeDefinitionId, xpath); + //store the match type + newCookie.MntpAddXPathFilterType(this.DataTypeDefinitionId, XPathFilterMatchType); + //store the start node id + newCookie.MntpAddStartNodeId(this.DataTypeDefinitionId, StartNodeId); + //store the start node selection type + newCookie.MntpAddStartNodeSelectionType(this.DataTypeDefinitionId, StartNodeSelectionType); + //store the start node xpath expression type + newCookie.MntpAddStartNodeXPathExpressionType(this.DataTypeDefinitionId, StartNodeXPathExpressionType); + //store the start node xpath expression + newCookie.MntpAddStartNodeXPathExpression(this.DataTypeDefinitionId, StartNodeXPathExpression); + //store the current editing node if found + if (!string.IsNullOrEmpty(HttpContext.Current.Request["id"])) + { + var id = 0; + if (int.TryParse(HttpContext.Current.Request["id"], out id)) + { + newCookie.MntpAddCurrentEditingNode(this.DataTypeDefinitionId, id); + } + } + + HttpContext.Current.Response.Cookies.Add(newCookie); + + //add it to the request cookies too, thus overriding any old data + if (HttpContext.Current.Request.Cookies[MNTP_DataType.PersistenceCookieName] != null && HttpContext.Current.Request.Cookies[MNTP_DataType.PersistenceCookieName].Values.Count > 0) + { + //remove the incoming one and replace with new one + HttpContext.Current.Request.Cookies.Remove(MNTP_DataType.PersistenceCookieName); + } + HttpContext.Current.Request.Cookies.Add(newCookie); + + } + + /// + /// A reference path to where the icons are actually stored as compared to where the tree themes folder is + /// + private static readonly string IconPath = IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/images/umbraco/"; + } } From c4f1235f0b96258f6479c04efd78711486bc2b42 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 11 Oct 2012 03:02:23 +0500 Subject: [PATCH 09/15] Fixes issues with ApplicationRegistrar and ApplicationTreeRegistrar during install, they now check if the application is configured, if not then they exit otherwise exceptions will be logged every time the app starts during install. Added a log on application end with the reason for shutdown and nicer methods to override in global.asax. --- src/Umbraco.Web/UmbracoApplication.cs | 33 +++++++++++++++++-- .../ApplicationRegistrar.cs | 32 +++++++++++------- .../ApplicationTreeRegistrar.cs | 4 +++ 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index 81f3e019d8..de200db55c 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -3,7 +3,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; +using System.Web; +using System.Web.Hosting; using Umbraco.Core; +using Umbraco.Core.Logging; using Umbraco.Web.Routing; using umbraco.businesslogic; @@ -60,14 +63,38 @@ namespace Umbraco.Web ApplicationStarted(sender, e); } - protected virtual void Application_Error(object sender, EventArgs e) + /// + /// A method that can be overridden to invoke code when the application has an error. + /// + /// + /// + protected virtual void OnApplicationError(object sender, EventArgs e) { - + } - protected virtual void Application_End(object sender, EventArgs e) + protected void Application_Error(object sender, EventArgs e) { + OnApplicationError(sender, e); + } + /// + /// A method that can be overridden to invoke code when the application shuts down. + /// + /// + /// + protected virtual void OnApplicationEnd(object sender, EventArgs e) + { + + } + + protected void Application_End(object sender, EventArgs e) + { + if (SystemUtilities.GetCurrentTrustLevel() == AspNetHostingPermissionLevel.Unrestricted) + { + LogHelper.Info("Application shutdown. Reason: " + HostingEnvironment.ShutdownReason); + } + OnApplicationEnd(sender, e); } } } diff --git a/src/umbraco.businesslogic/ApplicationRegistrar.cs b/src/umbraco.businesslogic/ApplicationRegistrar.cs index d29d50d90f..2432ad783c 100644 --- a/src/umbraco.businesslogic/ApplicationRegistrar.cs +++ b/src/umbraco.businesslogic/ApplicationRegistrar.cs @@ -1,4 +1,6 @@ -using System.Linq; +using System; +using System.Data.SqlClient; +using System.Linq; using System.Xml.Linq; using Umbraco.Core; using umbraco.BusinessLogic.Utils; @@ -29,6 +31,11 @@ namespace umbraco.BusinessLogic public ApplicationRegistrar() { + + //don't do anything if the application is not configured! + if (!ApplicationContext.Current.IsConfigured) + return; + // Load all Applications by attribute and add them to the XML config var types = PluginManager.Current.ResolveApplications(); @@ -40,7 +47,7 @@ namespace umbraco.BusinessLogic var allAliases = Application.getAll().Select(x => x.alias).Concat(attrs.Select(x => x.Alias)); var inString = "'" + string.Join("','", allAliases) + "'"; - + Application.LoadXml(doc => { foreach (var attr in attrs) @@ -51,16 +58,17 @@ namespace umbraco.BusinessLogic new XAttribute("icon", attr.Icon), new XAttribute("sortOrder", attr.SortOrder))); } - - var dbApps = SqlHelper.ExecuteReader("SELECT * FROM umbracoApp WHERE appAlias NOT IN ("+ inString +")"); - while (dbApps.Read()) - { - doc.Root.Add(new XElement("add", - new XAttribute("alias", dbApps.GetString("appAlias")), - new XAttribute("name", dbApps.GetString("appName")), - new XAttribute("icon", dbApps.GetString("appIcon")), - new XAttribute("sortOrder", dbApps.GetByte("sortOrder")))); - } + + var dbApps = SqlHelper.ExecuteReader("SELECT * FROM umbracoApp WHERE appAlias NOT IN (" + inString + ")"); + while (dbApps.Read()) + { + doc.Root.Add(new XElement("add", + new XAttribute("alias", dbApps.GetString("appAlias")), + new XAttribute("name", dbApps.GetString("appName")), + new XAttribute("icon", dbApps.GetString("appIcon")), + new XAttribute("sortOrder", dbApps.GetByte("sortOrder")))); + } + }, true); diff --git a/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs b/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs index 70f709c84f..97628bbacd 100644 --- a/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs +++ b/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs @@ -30,6 +30,10 @@ namespace umbraco.BusinessLogic public ApplicationTreeRegistrar() { + //don't do anything if the application is not configured! + if (!ApplicationContext.Current.IsConfigured) + return; + // Load all Trees by attribute and add them to the XML config var types = PluginManager.Current.ResolveAttributedTrees(); From 422a2a685c1a8b52606af2d0d09575be97545738 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 11 Oct 2012 03:42:18 +0500 Subject: [PATCH 10/15] Fixes: U4-1015, U4-1014 --- .../Templates/MasterPageHelperTests.cs | 25 +++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + .../template/MasterpageHelper.cs | 12 +++++---- .../businesslogic/template/Template.cs | 16 ++++++------ 4 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 src/Umbraco.Tests/Templates/MasterPageHelperTests.cs diff --git a/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs b/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs new file mode 100644 index 0000000000..f52b7b68d9 --- /dev/null +++ b/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using umbraco.cms.businesslogic.template; + +namespace Umbraco.Tests.Templates +{ + [TestFixture] + public class MasterPageHelperTests + { + + [TestCase(@"<%@ master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] + [TestCase(@"<%@ Master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] + [TestCase(@"<%@Master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] + [TestCase(@"<%@ Master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] + [TestCase(@"<%@master language=""C#"" masterpagefile=""~/masterpages/umbMaster.master"" autoeventwireup=""true"" %>")] + public void IsMasterPageSyntax(string design) + { + Assert.IsTrue(MasterPageHelper.IsMasterPageSyntax(design)); + } + + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 5bf1f48618..e8893f92a9 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -76,6 +76,7 @@ + diff --git a/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs index d0d2ba12da..33375dda77 100644 --- a/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs +++ b/src/umbraco.cms/businesslogic/template/MasterpageHelper.cs @@ -5,11 +5,12 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using Umbraco.Core; using Umbraco.Core.IO; namespace umbraco.cms.businesslogic.template { - internal class MasterpageHelper + internal class MasterPageHelper { internal static readonly string DefaultMasterTemplate = SystemDirectories.Umbraco + "/masterpages/default.master"; @@ -23,7 +24,7 @@ namespace umbraco.cms.businesslogic.template return IOHelper.MapPath(SystemDirectories.Masterpages + "/" + t.Alias.Replace(" ", "") + ".master"); } - internal static string CreateMasterpageFile(Template t, bool overWrite = false) + internal static string CreateMasterPage(Template t, bool overWrite = false) { string masterpageContent = ""; @@ -52,7 +53,7 @@ namespace umbraco.cms.businesslogic.template return masterpageContent; } - internal static string UpdateMasterpageFile(Template t, string currentAlias) + internal static string UpdateMasterPageFile(Template t, string currentAlias) { return SaveTemplateToFile(t, currentAlias); } @@ -112,7 +113,7 @@ namespace umbraco.cms.businesslogic.template { var c = template.Children; foreach (CMSNode cmn in c) - UpdateMasterpageFile(new Template(cmn.Id), null); + UpdateMasterPageFile(new Template(cmn.Id), null); } //then kill the old file.. @@ -144,7 +145,8 @@ namespace umbraco.cms.businesslogic.template internal static bool IsMasterPageSyntax(string code) { - return code.Contains("<%@ Master") || code.Contains(" Date: Thu, 11 Oct 2012 03:00:28 +0400 Subject: [PATCH 11/15] Folder Browser Enhancements - IE 7 Thumbnail list CSS corrections, Added labels to the thumbnail size setter, Capture/cancel the return key on the filter textbox. --- .../FolderBrowser/Css/folderbrowser.css | 2 ++ src/Umbraco.Web/UI/Controls/FolderBrowser.cs | 17 +++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Css/folderbrowser.css b/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Css/folderbrowser.css index def770222a..15eb8c0804 100644 --- a/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Css/folderbrowser.css +++ b/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Css/folderbrowser.css @@ -167,6 +167,8 @@ .umbFolderBrowser .items li { display: inline-block; + list-style: none; + float: left; } .umbFolderBrowser .items li div { diff --git a/src/Umbraco.Web/UI/Controls/FolderBrowser.cs b/src/Umbraco.Web/UI/Controls/FolderBrowser.cs index b8569730b2..421d9c369d 100644 --- a/src/Umbraco.Web/UI/Controls/FolderBrowser.cs +++ b/src/Umbraco.Web/UI/Controls/FolderBrowser.cs @@ -112,16 +112,16 @@ namespace Umbraco.Web.UI.Controls // Create size changer sb.Append("
    " + - "" + - "Small thumbnails" + - "" + - "Medium thumbnails" + - "" + - "Large thumbnails" + + "" + + "" + + "" + + "" + + "" + + "" + "
    "); // Create the filter input - sb.Append("
    Filter:
    "); + sb.Append("
    Filter:
    "); // Create throbber to display whilst loading items sb.Append(""); @@ -137,7 +137,8 @@ namespace Umbraco.Web.UI.Controls Page.ClientScript.RegisterStartupScript(typeof(FolderBrowser), "RegisterFolderBrowsers", - string.Format("$(function () {{ $(\".umbFolderBrowser\").folderBrowser({{ umbracoPath : '{0}', basePath : '{1}' }}); }});", + string.Format("$(function () {{ $(\".umbFolderBrowser\").folderBrowser({{ umbracoPath : '{0}', basePath : '{1}' }}); " + + "$(\".umbFolderBrowser #filterTerm\").keypress(function(event) {{ return event.keyCode != 13; }});}});", IOHelper.ResolveUrl(SystemDirectories.Umbraco), IOHelper.ResolveUrl(SystemDirectories.Base)), true); From a2988a30c03d5d5bbe4e66856aea6758a56f7b66 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 11 Oct 2012 07:54:04 +0500 Subject: [PATCH 12/15] updated ignore. Fixed issue when media is not found and YSOD is displayed. --- .hgignore | 1 + src/Umbraco.Web/DefaultPublishedMediaStore.cs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.hgignore b/.hgignore index f59589f44c..bbcd3f8e97 100644 --- a/.hgignore +++ b/.hgignore @@ -54,3 +54,4 @@ src/Umbraco.Web.UI/Views/*.cshtml src/Umbraco.Web.UI/Views/*.vbhtml src/Umbraco.Tests/config/umbracoSettings.config src/Umbraco.Web.UI/App_Plugins/* +src/Umbraco.Web.UI/Views/* diff --git a/src/Umbraco.Web/DefaultPublishedMediaStore.cs b/src/Umbraco.Web/DefaultPublishedMediaStore.cs index 7a3e9a66f8..35a5b30c3f 100644 --- a/src/Umbraco.Web/DefaultPublishedMediaStore.cs +++ b/src/Umbraco.Web/DefaultPublishedMediaStore.cs @@ -70,8 +70,17 @@ namespace Umbraco.Web var media = global::umbraco.library.GetMedia(id, true); if (media != null && media.Current != null) { - media.MoveNext(); - return ConvertFromXPathNavigator(media.Current); + if (media.MoveNext()) + { + var current = media.Current; + //error check + if (media.Current.MoveToFirstChild() && media.Current.Name.InvariantEquals("error")) + { + return null; + } + + return ConvertFromXPathNavigator(current); + } } return null; From b6f7d9903974f0b929046f91d0ecfff4a774a792 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 11 Oct 2012 08:32:06 +0500 Subject: [PATCH 13/15] Fixed why all the unit tests were failing. Ported over a couple of unit tests from the legacy test project to see how easy it would be and it looks pretty easy, just need the propery initialization data for the tests. Currently ported over the Dictionary biz logic tests.... most fail but pretty sure it's due to init data. --- .../BusinessLogic}/DictionaryTest.cs | 121 ++++++++---------- .../ContentStores/PublishContentStoreTests.cs | 3 +- .../Umbraco.Tests/IO}/IOHelperTest.cs | 66 ++-------- src/Umbraco.Tests/TestHelpers/BaseWebTest.cs | 8 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 2 + test/umbraco.Test/Umbraco.LegacyTests.csproj | 2 - 6 files changed, 69 insertions(+), 133 deletions(-) rename {test/umbraco.Test => src/Umbraco.Tests/BusinessLogic}/DictionaryTest.cs (85%) rename {test/umbraco.Test => src/Umbraco.Tests/IO}/IOHelperTest.cs (58%) diff --git a/test/umbraco.Test/DictionaryTest.cs b/src/Umbraco.Tests/BusinessLogic/DictionaryTest.cs similarity index 85% rename from test/umbraco.Test/DictionaryTest.cs rename to src/Umbraco.Tests/BusinessLogic/DictionaryTest.cs index b217c11ee2..a73e085e87 100644 --- a/test/umbraco.Test/DictionaryTest.cs +++ b/src/Umbraco.Tests/BusinessLogic/DictionaryTest.cs @@ -1,30 +1,39 @@ -using umbraco.cms.businesslogic; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Tests.TestHelpers; +using umbraco.cms.businesslogic; using System; using System.Xml; using umbraco.cms.businesslogic.language; using umbraco.BusinessLogic; using System.Linq; -namespace Umbraco.LegacyTests +namespace Umbraco.Tests.BusinessLogic { - + //TODO: This was ported over from the previous unit tests, need to make them work now :) /// ///This is a test class for Dictionary_DictionaryItemTest and is intended ///to contain all Dictionary_DictionaryItemTest Unit Tests /// - [TestClass()] - public class DictionaryTest + [TestFixture] + public class DictionaryTest : BaseWebTest { - [TestMethod()] + public override void Initialize() + { + base.Initialize(); + + CreateNew(); + } + + [Test()] public void Dictionary_Get_Top_Level_Items() { var items = Dictionary.getTopMostItems; var d = CreateNew(); - Assert.AreEqual(items.Count() + 1, Dictionary.getTopMostItems.Count()); + Assert.AreEqual(items.Count() + 1, Dictionary.getTopMostItems.Count()); DeleteItem(d); } @@ -33,7 +42,7 @@ namespace Umbraco.LegacyTests /// Creates a new dictionary entry, adds values for all languages assigned, then deletes the /// entry and ensure that all other data is gone too. /// - [TestMethod()] + [Test()] public void Dictionary_Create_Add_Text_And_Delete() { var d = CreateNew(); @@ -55,7 +64,7 @@ namespace Umbraco.LegacyTests /// ///A test for IsTopMostItem /// - [TestMethod()] + [Test()] public void Dictionary_IsTopMostItem() { var parent = CreateNew(); @@ -64,7 +73,7 @@ namespace Umbraco.LegacyTests var childId = Dictionary.DictionaryItem.addKey("Test" + Guid.NewGuid().ToString("N"), "", parent.key); Assert.IsTrue(childId > 0); var child = new Dictionary.DictionaryItem(childId); - Assert.IsInstanceOfType(child, typeof(Dictionary.DictionaryItem)); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(child)); Assert.IsTrue(parent.IsTopMostItem()); Assert.IsFalse(child.IsTopMostItem()); @@ -76,7 +85,7 @@ namespace Umbraco.LegacyTests /// /// Test the Parent and Children properties and ensures that the relationships work both ways /// - [TestMethod()] + [Test()] public void Dictionary_Parent_Child_Relationship() { var parent = CreateNew(); @@ -85,7 +94,7 @@ namespace Umbraco.LegacyTests var childId = Dictionary.DictionaryItem.addKey("Test" + Guid.NewGuid().ToString("N"), "", parent.key); Assert.IsTrue(childId > 0); var child = new Dictionary.DictionaryItem(childId); - Assert.IsInstanceOfType(child, typeof(Dictionary.DictionaryItem)); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(child)); //set the parent relationship Assert.AreEqual(parent.id, child.Parent.id); @@ -94,7 +103,7 @@ namespace Umbraco.LegacyTests //test the child relationship Assert.IsTrue(parent.hasChildren); - Assert.AreEqual(1, parent.Children.Length); + Assert.AreEqual(1, parent.Children.Length); Assert.AreEqual(child.id, parent.Children.First().id); Assert.AreEqual(child.key, parent.Children.First().key); Assert.AreEqual(child.UniqueId, parent.Children.First().UniqueId); @@ -106,7 +115,7 @@ namespace Umbraco.LegacyTests /// /// Deletes a parent with existing children and ensures they are all gone. /// - [TestMethod()] + [Test()] public void Dictionary_Delete_Parent_With_Children() { var parent = CreateNew(); @@ -115,16 +124,16 @@ namespace Umbraco.LegacyTests var childId1 = Dictionary.DictionaryItem.addKey("Test" + Guid.NewGuid().ToString("N"), "", parent.key); Assert.IsTrue(childId1 > 0); var child1 = new Dictionary.DictionaryItem(childId1); - Assert.IsInstanceOfType(child1, typeof(Dictionary.DictionaryItem)); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(child1)); //create a child var childId2 = Dictionary.DictionaryItem.addKey("Test" + Guid.NewGuid().ToString("N"), "", parent.key); Assert.IsTrue(childId2 > 0); var child2 = new Dictionary.DictionaryItem(childId2); - Assert.IsInstanceOfType(child2, typeof(Dictionary.DictionaryItem)); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(child2)); Assert.IsTrue(parent.hasChildren); - Assert.AreEqual(2, parent.Children.Length); + Assert.AreEqual(2, parent.Children.Length); DeleteItem(parent); @@ -157,7 +166,7 @@ namespace Umbraco.LegacyTests /// /// Guid constructor test /// - [TestMethod()] + [Test()] public void Dictionary_Contructor_Guid() { var d = CreateNew(); @@ -174,7 +183,7 @@ namespace Umbraco.LegacyTests /// /// key constructor test /// - [TestMethod()] + [Test()] public void Dictionary_Contructor_Key() { var d = CreateNew(); @@ -191,7 +200,7 @@ namespace Umbraco.LegacyTests /// ///A test for ToXml /// - [TestMethod()] + [Test()] public void Dictionary_ToXml() { var d = CreateNew(); @@ -200,7 +209,7 @@ namespace Umbraco.LegacyTests var childId = Dictionary.DictionaryItem.addKey("Test" + Guid.NewGuid().ToString("N"), "", d.key); Assert.IsTrue(childId > 0); var child = new Dictionary.DictionaryItem(childId); - Assert.IsInstanceOfType(child, typeof(Dictionary.DictionaryItem)); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(child)); var xml = new XmlDocument(); @@ -218,7 +227,7 @@ namespace Umbraco.LegacyTests /// ///A test to change the key of an element /// - [TestMethod()] + [Test()] public void Dictionary_Change_Key() { //System.Diagnostics.Debugger.Break(); @@ -247,14 +256,14 @@ namespace Umbraco.LegacyTests /// /// Tries to create a duplicate key and ensures it's not possible. /// - [TestMethod()] + [Test()] public void Dictionary_Attempt_Duplicate_Key() { var key = "Test" + Guid.NewGuid().ToString("N"); var d1Id = Dictionary.DictionaryItem.addKey(key, ""); Assert.IsTrue(d1Id > 0); var d1 = new Dictionary.DictionaryItem(d1Id); - Assert.IsInstanceOfType(d1, typeof(Dictionary.DictionaryItem)); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(d1)); var alreadyExists = false; try @@ -273,13 +282,14 @@ namespace Umbraco.LegacyTests } #region Private methods + private Dictionary.DictionaryItem CreateNew() { var id = Dictionary.DictionaryItem.addKey("Test" + Guid.NewGuid().ToString("N"), ""); Assert.IsTrue(id > 0); var d = new Dictionary.DictionaryItem(id); - Assert.IsInstanceOfType(d, typeof(Dictionary.DictionaryItem)); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(d)); return d; } @@ -314,7 +324,7 @@ namespace Umbraco.LegacyTests ///// /////A test for Import ///// - //[TestMethod()] + //[Test()] //public void ImportTest() //{ // XmlNode xmlData = null; // TODO: Initialize to an appropriate value @@ -329,7 +339,7 @@ namespace Umbraco.LegacyTests ///// /////A test for Import ///// - //[TestMethod()] + //[Test()] //public void ImportTest1() //{ // XmlNode xmlData = null; // TODO: Initialize to an appropriate value @@ -345,7 +355,7 @@ namespace Umbraco.LegacyTests ///// /////A test for Save ///// - //[TestMethod()] + //[Test()] //public void SaveTest() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -359,7 +369,7 @@ namespace Umbraco.LegacyTests ///// /////A test for Value ///// - //[TestMethod()] + //[Test()] //public void ValueTest() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -375,7 +385,7 @@ namespace Umbraco.LegacyTests ///// /////A test for Value ///// - //[TestMethod()] + //[Test()] //public void ValueTest1() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -390,7 +400,7 @@ namespace Umbraco.LegacyTests ///// /////A test for addKey ///// - //[TestMethod()] + //[Test()] //public void addKeyTest() //{ // string key = string.Empty; // TODO: Initialize to an appropriate value @@ -405,7 +415,7 @@ namespace Umbraco.LegacyTests ///// /////A test for addKey ///// - //[TestMethod()] + //[Test()] //public void addKeyTest1() //{ // string key = string.Empty; // TODO: Initialize to an appropriate value @@ -421,7 +431,7 @@ namespace Umbraco.LegacyTests ///// /////A test for delete ///// - //[TestMethod()] + //[Test()] //public void deleteTest() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -433,7 +443,7 @@ namespace Umbraco.LegacyTests ///// /////A test for hasKey ///// - //[TestMethod()] + //[Test()] //public void hasKeyTest() //{ // string key = string.Empty; // TODO: Initialize to an appropriate value @@ -447,7 +457,7 @@ namespace Umbraco.LegacyTests ///// /////A test for setValue ///// - //[TestMethod()] + //[Test()] //public void setValueTest() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -461,7 +471,7 @@ namespace Umbraco.LegacyTests ///// /////A test for setValue ///// - //[TestMethod()] + //[Test()] //public void setValueTest1() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -474,7 +484,7 @@ namespace Umbraco.LegacyTests ///// /////A test for Children ///// - //[TestMethod()] + //[Test()] //public void ChildrenTest() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -487,7 +497,7 @@ namespace Umbraco.LegacyTests ///// /////A test for Parent ///// - //[TestMethod()] + //[Test()] //public void ParentTest() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -500,7 +510,7 @@ namespace Umbraco.LegacyTests ///// /////A test for hasChildren ///// - //[TestMethod()] + //[Test()] //public void hasChildrenTest() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -513,7 +523,7 @@ namespace Umbraco.LegacyTests ///// /////A test for id ///// - //[TestMethod()] + //[Test()] //public void idTest() //{ // Guid id = new Guid(); // TODO: Initialize to an appropriate value @@ -526,34 +536,5 @@ namespace Umbraco.LegacyTests #endregion - #region Initialize and Cleanup - // - //You can use the following additional attributes as you write your tests: - // - //Use ClassInitialize to run code before running the first test in the class - //[ClassInitialize()] - //public static void MyClassInitialize(TestContext testContext) - //{ - //} - // - //Use ClassCleanup to run code after all tests in a class have run - //[ClassCleanup()] - //public static void MyClassCleanup() - //{ - //} - // - //Use TestInitialize to run code before running each test - //[TestInitialize()] - //public void MyTestInitialize() - //{ - //} - // - //Use TestCleanup to run code after each test has run - //[TestCleanup()] - //public void MyTestCleanup() - //{ - //} - // - #endregion } } diff --git a/src/Umbraco.Tests/ContentStores/PublishContentStoreTests.cs b/src/Umbraco.Tests/ContentStores/PublishContentStoreTests.cs index d8f7831e3e..e4e19a6b18 100644 --- a/src/Umbraco.Tests/ContentStores/PublishContentStoreTests.cs +++ b/src/Umbraco.Tests/ContentStores/PublishContentStoreTests.cs @@ -5,10 +5,9 @@ using Umbraco.Core; using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.Routing; -using umbraco; using umbraco.BusinessLogic; -namespace Umbraco.Tests +namespace Umbraco.Tests.ContentStores { [TestFixture] public class PublishContentStoreTests diff --git a/test/umbraco.Test/IOHelperTest.cs b/src/Umbraco.Tests/IO/IOHelperTest.cs similarity index 58% rename from test/umbraco.Test/IOHelperTest.cs rename to src/Umbraco.Tests/IO/IOHelperTest.cs index ab4d382e95..d23d5cba5f 100644 --- a/test/umbraco.Test/IOHelperTest.cs +++ b/src/Umbraco.Tests/IO/IOHelperTest.cs @@ -1,7 +1,7 @@ -using umbraco.IO; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using NUnit.Framework; +using Umbraco.Core.IO; -namespace Umbraco.LegacyTests +namespace Umbraco.Tests.IO { @@ -9,64 +9,14 @@ namespace Umbraco.LegacyTests ///This is a test class for IOHelperTest and is intended ///to contain all IOHelperTest Unit Tests /// - [TestClass()] + [TestFixture()] public class IOHelperTest { - - private TestContext testContextInstance; - - /// - ///Gets or sets the test context which provides - ///information about and functionality for the current test run. - /// - public TestContext TestContext - { - get - { - return testContextInstance; - } - set - { - testContextInstance = value; - } - } - - #region Additional test attributes - // - //You can use the following additional attributes as you write your tests: - // - //Use ClassInitialize to run code before running the first test in the class - //[ClassInitialize()] - //public static void MyClassInitialize(TestContext testContext) - //{ - //} - // - //Use ClassCleanup to run code after all tests in a class have run - //[ClassCleanup()] - //public static void MyClassCleanup() - //{ - //} - // - //Use TestInitialize to run code before running each test - //[TestInitialize()] - //public void MyTestInitialize() - //{ - //} - // - //Use TestCleanup to run code after each test has run - //[TestCleanup()] - //public void MyTestCleanup() - //{ - //} - // - #endregion - - /// ///A test for MapPath verifying that HttpContext method (which includes vdirs) matches non-HttpContext method /// - [TestMethod()] + [Test] public void IOHelper_MapPathTestVDirTraversal() { //System.Diagnostics.Debugger.Break(); @@ -84,9 +34,9 @@ namespace Umbraco.LegacyTests Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Root, true), IOHelper.MapPath(SystemDirectories.Root, false)); Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Scripts, true), IOHelper.MapPath(SystemDirectories.Scripts, false)); Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Umbraco, true), IOHelper.MapPath(SystemDirectories.Umbraco, false)); - Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Umbraco_client, true), IOHelper.MapPath(SystemDirectories.Umbraco_client, false)); - Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Usercontrols, true), IOHelper.MapPath(SystemDirectories.Usercontrols, false)); - Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Webservices, true), IOHelper.MapPath(SystemDirectories.Webservices, false)); + Assert.AreEqual(IOHelper.MapPath(SystemDirectories.UmbracoClient, true), IOHelper.MapPath(SystemDirectories.UmbracoClient, false)); + Assert.AreEqual(IOHelper.MapPath(SystemDirectories.UserControls, true), IOHelper.MapPath(SystemDirectories.UserControls, false)); + Assert.AreEqual(IOHelper.MapPath(SystemDirectories.WebServices, true), IOHelper.MapPath(SystemDirectories.WebServices, false)); Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Xslt, true), IOHelper.MapPath(SystemDirectories.Xslt, false)); } } diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 1b1076cb08..2009d7d683 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Web.Routing; using System.Xml; @@ -14,7 +15,7 @@ using umbraco.cms.businesslogic.template; namespace Umbraco.Tests.TestHelpers { - [TestFixture] + [TestFixture, RequiresSTA] public abstract class BaseWebTest { @@ -22,6 +23,9 @@ namespace Umbraco.Tests.TestHelpers public virtual void Initialize() { TestHelper.SetupLog4NetForTests(); + + AppDomain.CurrentDomain.SetData("DataDirectory", TestHelper.CurrentAssemblyDirectory); + if (RequiresDbSetup) TestHelper.InitializeDatabase(); Resolution.Freeze(); @@ -36,6 +40,8 @@ namespace Umbraco.Tests.TestHelpers [TearDown] public virtual void TearDown() { + AppDomain.CurrentDomain.SetData("DataDirectory", null); + //reset the app context ApplicationContext.Current = null; Resolution.IsFrozen = false; diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e8893f92a9..b389798cf8 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -53,10 +53,12 @@ + + diff --git a/test/umbraco.Test/Umbraco.LegacyTests.csproj b/test/umbraco.Test/Umbraco.LegacyTests.csproj index 2876f15ebd..942d01a6a4 100644 --- a/test/umbraco.Test/Umbraco.LegacyTests.csproj +++ b/test/umbraco.Test/Umbraco.LegacyTests.csproj @@ -122,10 +122,8 @@ Properties\SolutionInfo.cs - - From a3b87a1d8beef816420d148e3d388da70c48d2bd Mon Sep 17 00:00:00 2001 From: Casey Neehouse Date: Thu, 11 Oct 2012 13:02:36 +0400 Subject: [PATCH 14/15] Wraps Code Editor initialization in a document ready call to correct an IE7 sizing bug. --- src/umbraco.controls/CodeArea.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/umbraco.controls/CodeArea.cs b/src/umbraco.controls/CodeArea.cs index 7d3c9e1392..ba446b0cea 100644 --- a/src/umbraco.controls/CodeArea.cs +++ b/src/umbraco.controls/CodeArea.cs @@ -171,17 +171,17 @@ namespace umbraco.uicontrols } jsEventCode += @" - - //create the editor - var UmbEditor = new Umbraco.Controls.CodeEditor.UmbracoEditor(" + (!CodeMirrorEnabled).ToString().ToLower() + @", '" + this.ClientID + @"'); - var m_textEditor = jQuery('#" + this.ClientID + @"'); + $(function () { + //create the editor + var UmbEditor = new Umbraco.Controls.CodeEditor.UmbracoEditor(" + (!CodeMirrorEnabled).ToString().ToLower() + @", '" + this.ClientID + @"'); + var m_textEditor = jQuery('#" + this.ClientID + @"'); - //with codemirror adding divs for line numbers, we need to target a different element - m_textEditor = m_textEditor.find('iframe').length > 0 ? m_textEditor.children('div').get(0) : m_textEditor.get(0); + //with codemirror adding divs for line numbers, we need to target a different element + m_textEditor = m_textEditor.find('iframe').length > 0 ? m_textEditor.children('div').get(0) : m_textEditor.get(0); - jQuery(window).resize(function(){ resizeTextArea(m_textEditor, " + OffSetX.ToString() + "," + OffSetY.ToString() + @"); }); - jQuery(document).ready(function(){ resizeTextArea(m_textEditor, " + OffSetX.ToString() + "," + OffSetY.ToString() + @"); });"; - + jQuery(window).resize(function(){ resizeTextArea(m_textEditor, " + OffSetX.ToString() + "," + OffSetY.ToString() + @"); }); + jQuery(document).ready(function(){ resizeTextArea(m_textEditor, " + OffSetX.ToString() + "," + OffSetY.ToString() + @"); }); + });"; /* if (!UmbracoSettings.ScriptDisableEditor && HttpContext.Current.Request.Browser.Browser == "IE") { From 65d5bc915534dc2a282be33265cefbc4d8b7cdb7 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 11 Oct 2012 08:42:20 -0200 Subject: [PATCH 15/15] Change from enableMvcSupport to defaultRenderingEngine in the release config too --- src/Umbraco.Web.UI/config/umbracoSettings.Release.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config index 057945415a..d62cc88e51 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config @@ -129,8 +129,8 @@ - true - false + true + WebForms