diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings.cs index bf9d8373d8..a67e0cd279 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings.cs @@ -1255,6 +1255,41 @@ namespace Umbraco.Core.Configuration return _macroErrorBehaviour.Value; } } + + private static IconPickerBehaviour? _iconPickerBehaviour; + + /// + /// This configuration setting defines how to show icons in the document type editor. + /// - ShowDuplicates - Show duplicates in files and sprites. (default and current Umbraco 'normal' behaviour) + /// - HideSpriteDuplicates - Show files on disk and hide duplicates from the sprite + /// - HideFileDuplicates - Show files in the sprite and hide duplicates on disk + /// + /// MacroErrorBehaviour enum defining how to show icons in the document type editor. + public static IconPickerBehaviour IconPickerBehaviour + { + get + { + if (_iconPickerBehaviour == null) + { + try + { + var behaviour = IconPickerBehaviour.ShowDuplicates; + var value = GetKey("/settings/content/DocumentTypeIconList"); + if (value != null) + { + Enum.TryParse(value, true, out behaviour); + } + _iconPickerBehaviour = behaviour; + } + catch (Exception ex) + { + LogHelper.Error("Could not load /settings/content/DocumentTypeIconList from umbracosettings.config", ex); + _iconPickerBehaviour = IconPickerBehaviour.ShowDuplicates; + } + } + return _iconPickerBehaviour.Value; + } + } /// /// Configuration regarding webservices diff --git a/src/Umbraco.Core/IconPickerBehaviour.cs b/src/Umbraco.Core/IconPickerBehaviour.cs new file mode 100644 index 0000000000..d442bbe95d --- /dev/null +++ b/src/Umbraco.Core/IconPickerBehaviour.cs @@ -0,0 +1,24 @@ +namespace Umbraco.Core +{ + public enum IconPickerBehaviour + { + /// + /// Default umbraco behavior - show duplicates in files and sprites + /// + ShowDuplicates, + + /// + /// If a file exists on disk with the same name as one in the sprite + /// then the file on disk overrules the one in the sprite, the + /// sprite icon will not be shown + /// + HideSpriteDuplicates, + + /// + /// If a file exists on disk with the same name as one in the sprite + /// then the file in the sprite overrules the one on disk, the file + /// on disk will be shown + /// + HideFileDuplicates + } +} diff --git a/src/Umbraco.Core/Models/UmbracoEntity.cs b/src/Umbraco.Core/Models/UmbracoEntity.cs index 4791606d2c..f3ab2b71e0 100644 --- a/src/Umbraco.Core/Models/UmbracoEntity.cs +++ b/src/Umbraco.Core/Models/UmbracoEntity.cs @@ -20,6 +20,8 @@ namespace Umbraco.Core.Models private bool _isPublished; private bool _isDraft; private bool _hasPendingChanges; + private string _contentTypeAlias; + private string _umbracoFile; private Guid _nodeObjectTypeId; private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId); @@ -33,7 +35,13 @@ namespace Umbraco.Core.Models private static readonly PropertyInfo IsPublishedSelector = ExpressionHelper.GetPropertyInfo(x => x.IsPublished); private static readonly PropertyInfo IsDraftSelector = ExpressionHelper.GetPropertyInfo(x => x.IsDraft); private static readonly PropertyInfo HasPendingChangesSelector = ExpressionHelper.GetPropertyInfo(x => x.HasPendingChanges); + private static readonly PropertyInfo ContentTypeAliasSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeAlias); + private static readonly PropertyInfo ContentTypeIconSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeIcon); + private static readonly PropertyInfo ContentTypeThumbnailSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeThumbnail); + private static readonly PropertyInfo UmbracoFileSelector = ExpressionHelper.GetPropertyInfo(x => x.UmbracoFile); private static readonly PropertyInfo NodeObjectTypeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.NodeObjectTypeId); + private string _contentTypeIcon; + private string _contentTypeThumbnail; public UmbracoEntity() { @@ -187,6 +195,58 @@ namespace Umbraco.Core.Models } } + public string ContentTypeAlias + { + get { return _contentTypeAlias; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _contentTypeAlias = value; + return _contentTypeAlias; + }, _contentTypeAlias, ContentTypeAliasSelector); + } + } + + public string ContentTypeIcon + { + get { return _contentTypeIcon; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _contentTypeIcon = value; + return _contentTypeIcon; + }, _contentTypeIcon, ContentTypeIconSelector); + } + } + + public string ContentTypeThumbnail + { + get { return _contentTypeThumbnail; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _contentTypeThumbnail = value; + return _contentTypeThumbnail; + }, _contentTypeThumbnail, ContentTypeThumbnailSelector); + } + } + + public string UmbracoFile + { + get { return _umbracoFile; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _umbracoFile = value; + return _umbracoFile; + }, _umbracoFile, UmbracoFileSelector); + } + } + public Guid NodeObjectTypeId { get { return _nodeObjectTypeId; } diff --git a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs index e3fec16cf4..e26b43f5a6 100644 --- a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs @@ -21,7 +21,11 @@ namespace Umbraco.Core.Persistence.Factories ParentId = dto.ParentId, Path = dto.Path, SortOrder = dto.SortOrder, - HasChildren = dto.Children > 0 + HasChildren = dto.Children > 0, + ContentTypeAlias = dto.Alias ?? string.Empty, + ContentTypeIcon = dto.Icon ?? string.Empty, + ContentTypeThumbnail = dto.Thumbnail ?? string.Empty, + UmbracoFile = dto.UmbracoFile ?? string.Empty }; entity.IsPublished = dto.PublishedVersion != default(Guid) || diff --git a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs index a4a0e08e5d..2a898006e4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs @@ -58,8 +58,8 @@ namespace Umbraco.Core.Persistence.Repositories public virtual IUmbracoEntity Get(int id, Guid objectTypeId) { - bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document); - var sql = GetBaseWhere(GetBase, isContent, objectTypeId, id).Append(GetGroupBy(isContent)); + bool isContentOrMedia = objectTypeId == new Guid(Constants.ObjectTypes.Document) || objectTypeId == new Guid(Constants.ObjectTypes.Media); + var sql = GetBaseWhere(GetBase, isContentOrMedia, objectTypeId, id).Append(GetGroupBy(isContentOrMedia)); var nodeDto = _work.Database.FirstOrDefault(sql); if (nodeDto == null) return null; @@ -81,8 +81,8 @@ namespace Umbraco.Core.Persistence.Repositories } else { - bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document); - var sql = GetBaseWhere(GetBase, isContent, objectTypeId).Append(GetGroupBy(isContent)); + bool isContentOrMedia = objectTypeId == new Guid(Constants.ObjectTypes.Document) || objectTypeId == new Guid(Constants.ObjectTypes.Media); + var sql = GetBaseWhere(GetBase, isContentOrMedia, objectTypeId).Append(GetGroupBy(isContentOrMedia)); var dtos = _work.Database.Fetch(sql); var factory = new UmbracoEntityFactory(); @@ -111,10 +111,10 @@ namespace Umbraco.Core.Persistence.Repositories public virtual IEnumerable GetByQuery(IQuery query, Guid objectTypeId) { - bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document); - var sqlClause = GetBaseWhere(GetBase, isContent, objectTypeId); + bool isContentOrMedia = objectTypeId == new Guid(Constants.ObjectTypes.Document) || objectTypeId == new Guid(Constants.ObjectTypes.Media); + var sqlClause = GetBaseWhere(GetBase, isContentOrMedia, objectTypeId); var translator = new SqlTranslator(sqlClause, query); - var sql = translator.Translate().Append(GetGroupBy(isContent)); + var sql = translator.Translate().Append(GetGroupBy(isContentOrMedia)); var dtos = _work.Database.Fetch(sql); @@ -128,94 +128,112 @@ namespace Umbraco.Core.Persistence.Repositories #region Sql Statements - protected virtual Sql GetBase(bool isContent) + protected virtual Sql GetBase(bool isContentOrMedia) { var columns = new List { - "main.id", - "main.trashed", - "main.parentID", - "main.nodeUser", - "main.level", - "main.path", - "main.sortOrder", - "main.uniqueID", - "main.text", - "main.nodeObjectType", - "main.createDate", + "umbracoNode.id", + "umbracoNode.trashed", + "umbracoNode.parentID", + "umbracoNode.nodeUser", + "umbracoNode.level", + "umbracoNode.path", + "umbracoNode.sortOrder", + "umbracoNode.uniqueID", + "umbracoNode.text", + "umbracoNode.nodeObjectType", + "umbracoNode.createDate", "COUNT(parent.parentID) as children" }; - if (isContent) + if (isContentOrMedia) { columns.Add("published.versionId as publishedVerison"); columns.Add("latest.versionId as newestVersion"); + columns.Add("contenttype.alias"); + columns.Add("contenttype.icon"); + columns.Add("contenttype.thumbnail"); + columns.Add("property.dataNvarchar as umbracoFile"); } var sql = new Sql() .Select(columns.ToArray()) - .From("umbracoNode main") - .LeftJoin("umbracoNode parent").On("parent.parentID = main.id"); + .From("umbracoNode umbracoNode") + .LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id"); - if (isContent) + if (isContentOrMedia) { - sql.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published").On("main.id = published.nodeId"); - sql.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE newest = 1 GROUP BY nodeId, versionId) as latest").On("main.id = latest.nodeId"); + sql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id") + .LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType") + .LeftJoin( + "(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published") + .On("umbracoNode.id = published.nodeId") + .LeftJoin( + "(SELECT nodeId, versionId FROM cmsDocument WHERE newest = 1 GROUP BY nodeId, versionId) as latest") + .On("umbracoNode.id = latest.nodeId") + .LeftJoin( + "(SELECT contentNodeId, dataNvarchar FROM cmsPropertyData INNER JOIN cmsPropertyType ON cmsPropertyType.id = cmsPropertyData.propertytypeid"+ + " INNER JOIN cmsDataType ON cmsPropertyType.dataTypeId = cmsDataType.nodeId WHERE cmsDataType.controlId = '"+ Constants.PropertyEditors.UploadField +"') as property") + .On("umbracoNode.id = property.contentNodeId"); } return sql; } - protected virtual Sql GetBaseWhere(Func baseQuery, bool isContent, Guid id) + protected virtual Sql GetBaseWhere(Func baseQuery, bool isContentOrMedia, Guid id) { - var sql = baseQuery(isContent) - .Where("main.nodeObjectType = @NodeObjectType", new {NodeObjectType = id}); + var sql = baseQuery(isContentOrMedia) + .Where("umbracoNode.nodeObjectType = @NodeObjectType", new { NodeObjectType = id }); return sql; } - protected virtual Sql GetBaseWhere(Func baseQuery, bool isContent, int id) + protected virtual Sql GetBaseWhere(Func baseQuery, bool isContentOrMedia, int id) { - var sql = baseQuery(isContent) - .Where("main.id = @Id", new {Id = id}) - .Append(GetGroupBy(isContent)); + var sql = baseQuery(isContentOrMedia) + .Where("umbracoNode.id = @Id", new { Id = id }) + .Append(GetGroupBy(isContentOrMedia)); return sql; } - protected virtual Sql GetBaseWhere(Func baseQuery, bool isContent, Guid objectId, int id) + protected virtual Sql GetBaseWhere(Func baseQuery, bool isContentOrMedia, Guid objectId, int id) { - var sql = baseQuery(isContent) - .Where("main.id = @Id AND main.nodeObjectType = @NodeObjectType", + var sql = baseQuery(isContentOrMedia) + .Where("umbracoNode.id = @Id AND umbracoNode.nodeObjectType = @NodeObjectType", new {Id = id, NodeObjectType = objectId}); return sql; } - protected virtual Sql GetGroupBy(bool isContent) + protected virtual Sql GetGroupBy(bool isContentOrMedia) { var columns = new List { - "main.id", - "main.trashed", - "main.parentID", - "main.nodeUser", - "main.level", - "main.path", - "main.sortOrder", - "main.uniqueID", - "main.text", - "main.nodeObjectType", - "main.createDate" + "umbracoNode.id", + "umbracoNode.trashed", + "umbracoNode.parentID", + "umbracoNode.nodeUser", + "umbracoNode.level", + "umbracoNode.path", + "umbracoNode.sortOrder", + "umbracoNode.uniqueID", + "umbracoNode.text", + "umbracoNode.nodeObjectType", + "umbracoNode.createDate" }; - if (isContent) + if (isContentOrMedia) { columns.Add("published.versionId"); columns.Add("latest.versionId"); + columns.Add("contenttype.alias"); + columns.Add("contenttype.icon"); + columns.Add("contenttype.thumbnail"); + columns.Add("property.dataNvarchar"); } var sql = new Sql() .GroupBy(columns.ToArray()) - .OrderBy("main.sortOrder"); + .OrderBy("umbracoNode.sortOrder"); return sql; } @@ -246,6 +264,18 @@ namespace Umbraco.Core.Persistence.Repositories [Column("newestVerison")] public Guid NewestVersion { get; set; } + + [Column("alias")] + public string Alias { get; set; } + + [Column("icon")] + public string Icon { get; set; } + + [Column("thumbnail")] + public string Thumbnail { get; set; } + + [Column("umbracoFile")] + public string UmbracoFile { get; set; } } #endregion } diff --git a/src/Umbraco.Core/Services/EntityService.cs b/src/Umbraco.Core/Services/EntityService.cs index 5e0b68b239..e8bd53e9c6 100644 --- a/src/Umbraco.Core/Services/EntityService.cs +++ b/src/Umbraco.Core/Services/EntityService.cs @@ -164,13 +164,13 @@ namespace Umbraco.Core.Services /// /// Gets a collection of children by the parents Id /// - /// Id of the parent to retrieve children for + /// Id of the parent to retrieve children for /// An enumerable list of objects - public virtual IEnumerable GetChildren(int id) + public virtual IEnumerable GetChildren(int parentId) { using (var repository = _repositoryFactory.CreateEntityRepository(_uowProvider.GetUnitOfWork())) { - var query = Query.Builder.Where(x => x.ParentId == id); + var query = Query.Builder.Where(x => x.ParentId == parentId); var contents = repository.GetByQuery(query); return contents; @@ -180,15 +180,15 @@ namespace Umbraco.Core.Services /// /// Gets a collection of children by the parents Id and UmbracoObjectType /// - /// Id of the parent to retrieve children for + /// Id of the parent to retrieve children for /// UmbracoObjectType of the children to retrieve /// An enumerable list of objects - public virtual IEnumerable GetChildren(int id, UmbracoObjectTypes umbracoObjectType) + public virtual IEnumerable GetChildren(int parentId, UmbracoObjectTypes umbracoObjectType) { var objectTypeId = umbracoObjectType.GetGuid(); using (var repository = _repositoryFactory.CreateEntityRepository(_uowProvider.GetUnitOfWork())) { - var query = Query.Builder.Where(x => x.ParentId == id); + var query = Query.Builder.Where(x => x.ParentId == parentId); var contents = repository.GetByQuery(query, objectTypeId); return contents; diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index ac651f675f..1c93a4f56d 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -209,7 +209,7 @@ namespace Umbraco.Core.Services _importedContentTypes = new Dictionary(); var documentTypes = name.Equals("DocumentTypes") ? (from doc in element.Elements("DocumentType") select doc).ToList() - : new List {element.Element("DocumentType")}; + : new List {element}; //NOTE it might be an idea to sort the doctype XElements based on dependencies //before creating the doc types - should also allow for a better structure/inheritance support. foreach (var documentType in documentTypes) @@ -580,8 +580,19 @@ namespace Umbraco.Core.Services foreach (XElement tempElement in templateElements) { var dependencies = new List(); - if(tempElement.Element("Master") != null && string.IsNullOrEmpty(tempElement.Element("Master").Value) == false) + if (tempElement.Element("Master") != null && + string.IsNullOrEmpty(tempElement.Element("Master").Value) == false && + templateElements.Any(x => x.Element("Alias").Value == tempElement.Element("Master").Value)) + { dependencies.Add(tempElement.Element("Master").Value); + } + else if (tempElement.Element("Master") != null && + string.IsNullOrEmpty(tempElement.Element("Master").Value) == false && + templateElements.Any(x => x.Element("Alias").Value == tempElement.Element("Master").Value) == + false) + { + LogHelper.Info(string.Format("Template '{0}' has an invalid Master '{1}', so the reference has been ignored.", tempElement.Element("Alias").Value, tempElement.Element("Master").Value)); + } var field = new TopologicalSorter.DependencyField { diff --git a/src/Umbraco.Core/TopologicalSorter.cs b/src/Umbraco.Core/TopologicalSorter.cs index b62628538a..436a247f5e 100644 --- a/src/Umbraco.Core/TopologicalSorter.cs +++ b/src/Umbraco.Core/TopologicalSorter.cs @@ -139,9 +139,15 @@ namespace Umbraco.Core { if (fields[i].DependsOn != null) { - foreach (string t in fields[i].DependsOn.Where(t => indexes.ContainsKey(t.ToLowerInvariant()))) + for (int j = 0; j < fields[i].DependsOn.Length; j++) { - g.AddEdge(i,indexes[t.ToLowerInvariant()]); + if (indexes.ContainsKey(fields[i].DependsOn[j].ToLowerInvariant()) == false) + throw new IndexOutOfRangeException( + string.Format( + "The alias '{0}' has an invalid dependency. The dependency '{1}' does not exist in the list of aliases", + fields[i], fields[i].DependsOn[j])); + + g.AddEdge(i, indexes[fields[i].DependsOn[j].ToLowerInvariant()]); } } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 95bedb1f6d..7a170ea4c2 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -164,6 +164,7 @@ + diff --git a/src/Umbraco.Tests/CoreStrings/LegacyShortStringHelperTests.cs b/src/Umbraco.Tests/CoreStrings/LegacyShortStringHelperTests.cs index ec19f59176..8df226e853 100644 --- a/src/Umbraco.Tests/CoreStrings/LegacyShortStringHelperTests.cs +++ b/src/Umbraco.Tests/CoreStrings/LegacyShortStringHelperTests.cs @@ -81,10 +81,10 @@ namespace Umbraco.Tests.CoreStrings } #region Cases - [TestCase("Home Page", "Home-Page")] - [TestCase("Shannon's Home Page!", "Shannons-Home-Page!")] - [TestCase("#Someones's Twitter $h1z%n", "Someoness-Twitter-$h1zn")] - [TestCase("Räksmörgås", "Raeksmoergaas")] + [TestCase("Home Page", "home-page")] + [TestCase("Shannon's Home Page!", "shannons-home-page!")] + [TestCase("#Someones's Twitter $h1z%n", "someoness-twitter-$h1zn")] + [TestCase("Räksmörgås", "raeksmoergaas")] [TestCase("'em guys-over there, are#goin' a \"little\"bit crazy eh!! :)", "em-guys-over-there,-aregoin-a-littlebit-crazy-eh!!-)")] [TestCase("汉#字*/漢?字", "汉字star漢字")] [TestCase("Réalösk fix bran#lo'sk", "realosk-fix-bran-lo-sk", IgnoreReason = "cannot handle it")] diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index 50fc198dca..4db386e3a4 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -18,7 +18,7 @@ namespace Umbraco.Tests.PublishedContent public override void Initialize() { base.Initialize(); - + UmbracoSettings.SettingsFilePath = Core.IO.IOHelper.MapPath(Core.IO.SystemDirectories.Config + Path.DirectorySeparatorChar, false); //need to specify a custom callback for unit tests diff --git a/src/Umbraco.Tests/Services/BaseServiceTest.cs b/src/Umbraco.Tests/Services/BaseServiceTest.cs index 56b94dcbf1..cd4318b5a6 100644 --- a/src/Umbraco.Tests/Services/BaseServiceTest.cs +++ b/src/Umbraco.Tests/Services/BaseServiceTest.cs @@ -1,11 +1,8 @@ using System; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; -using umbraco.editorControls.tinyMCE3; -using umbraco.interfaces; namespace Umbraco.Tests.Services { @@ -26,7 +23,7 @@ namespace Umbraco.Tests.Services base.TearDown(); } - public void CreateTestData() + public virtual void CreateTestData() { //NOTE Maybe not the best way to create/save test data as we are using the services, which are being tested. diff --git a/src/Umbraco.Tests/Services/EntityServiceTests.cs b/src/Umbraco.Tests/Services/EntityServiceTests.cs index abf541883f..dce19cb80a 100644 --- a/src/Umbraco.Tests/Services/EntityServiceTests.cs +++ b/src/Umbraco.Tests/Services/EntityServiceTests.cs @@ -3,6 +3,7 @@ using System.Linq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.Services { @@ -61,6 +62,18 @@ namespace Umbraco.Tests.Services Assert.That(entities.Any(x => x.Trashed), Is.True); } + [Test] + public void EntityService_Can_Get_Child_Content_By_ParentId_And_UmbracoObjectType() + { + var service = ServiceContext.EntityService; + + var entities = service.GetChildren(-1, UmbracoObjectTypes.Document); + + Assert.That(entities.Any(), Is.True); + Assert.That(entities.Count(), Is.EqualTo(1)); + Assert.That(entities.Any(x => x.Trashed), Is.False); + } + [Test] public void EntityService_Throws_When_Getting_All_With_Invalid_Type() { @@ -105,5 +118,37 @@ namespace Umbraco.Tests.Services Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(1)); } + + [Test] + public void EntityService_Can_Find_All_Media_By_UmbracoObjectTypes() + { + var service = ServiceContext.EntityService; + + var entities = service.GetAll(UmbracoObjectTypes.Media); + + Assert.That(entities.Any(), Is.True); + Assert.That(entities.Count(), Is.EqualTo(3)); + Assert.That(entities.Any(x => ((UmbracoEntity)x).UmbracoFile != string.Empty), Is.True); + } + + public override void CreateTestData() + { + base.CreateTestData(); + + //Create and Save folder-Media -> 1050 + var folderMediaType = ServiceContext.ContentTypeService.GetMediaType(1031); + var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1); + ServiceContext.MediaService.Save(folder, 0); + + //Create and Save image-Media -> 1051 + var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032); + var image = MockedMedia.CreateMediaImage(imageMediaType, folder.Id); + ServiceContext.MediaService.Save(image, 0); + + //Create and Save file-Media -> 1052 + var fileMediaType = ServiceContext.ContentTypeService.GetMediaType(1033); + var file = MockedMedia.CreateMediaFile(fileMediaType, folder.Id); + ServiceContext.MediaService.Save(file, 0); + } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs b/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs index fe580b782b..a465d0762a 100644 --- a/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs +++ b/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs @@ -136,5 +136,32 @@ namespace Umbraco.Tests.Services.Importing { return ResourceManager.GetString("uBlogsy_Package", resourceCulture); } } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files> + /// <file> + /// <guid>XSLTsearch.xslt</guid> + /// <orgPath>/xslt</orgPath> + /// <orgName>XSLTsearch.xslt</orgName> + /// </file> + /// <file> + /// <guid>XSLTsearch.cs</guid> + /// <orgPath>/App_Code</orgPath> + /// <orgName>XSLTsearch.cs</orgName> + /// </file> + /// </files> + /// <info> + /// <package> + /// <name>XSLTsearch</name> + /// <version>3.0.4</version> + /// <license url="http://www.opensource.org/licenses/mit-li [rest of string was truncated]";. + /// + internal static string XsltSearch_Package { + get { + return ResourceManager.GetString("XsltSearch_Package", resourceCulture); + } + } } } diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.resx b/src/Umbraco.Tests/Services/Importing/ImportResources.resx index 6fd3b9cf87..cc7d59a7eb 100644 --- a/src/Umbraco.Tests/Services/Importing/ImportResources.resx +++ b/src/Umbraco.Tests/Services/Importing/ImportResources.resx @@ -127,4 +127,7 @@ ublogsy-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + xsltsearch-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs index 287ebd0c94..5dc1a697a2 100644 --- a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs +++ b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs @@ -188,5 +188,23 @@ namespace Umbraco.Tests.Services.Importing Assert.That(contents.Any(), Is.True); Assert.That(contents.Count(), Is.EqualTo(numberOfDocs)); } + + [Test] + public void PackagingService_Can_Import_Templates_Package_Xml_With_Invalid_Master() + { + // Arrange + string strXml = ImportResources.XsltSearch_Package; + var xml = XElement.Parse(strXml); + var templateElement = xml.Descendants("Templates").First(); + var packagingService = ServiceContext.PackagingService; + + // Act + var templates = packagingService.ImportTemplates(templateElement); + var numberOfTemplates = (from doc in templateElement.Elements("Template") select doc).Count(); + + // Assert + Assert.That(templates.Any(), Is.True); + Assert.That(templates.Count(), Is.EqualTo(numberOfTemplates)); + } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/XsltSearch-Package.xml b/src/Umbraco.Tests/Services/Importing/XsltSearch-Package.xml new file mode 100644 index 0000000000..8096cfb833 --- /dev/null +++ b/src/Umbraco.Tests/Services/Importing/XsltSearch-Package.xml @@ -0,0 +1,254 @@ + + + + + XSLTsearch.xslt + /xslt + XSLTsearch.xslt + + + XSLTsearch.cs + /App_Code + XSLTsearch.cs + + + + + XSLTsearch + 3.0.4 + MIT license + http://www.percipientstudios.com + + 3 + 0 + 0 + + + + Percipient Studios + http://www.percipientstudios.com + + + + + + + + + 0 + + + + + + + XSLTsearch + XSLTsearch + .sprTreeDoc2 + doc.png + + XSLTsearch page. + (adjust settings via the macro in the XSLTsearch template) + + + XSLTsearch + + XSLTsearch + + + + + Hide in navigation + umbracoNaviHide + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + + + False + + + + + + + + + + + XSLTsearch + XSLTsearch + RunwayMaster + + + + + + + + + + + + + + +]]> + + + + + + XSLTsearch + + + + + + + + + + XSLTsearch + XSLTsearch + + + + + XSLTsearch.xslt + False + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + \ No newline at end of file diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 101c5c7ccc..95e89468c3 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.TestHelpers { base.Initialize(); } - + [TearDown] public override void TearDown() { diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 15e87f1b40..5254f18d0f 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -494,6 +494,7 @@ Designer + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index f061f7369b..9550a18117 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -378,6 +378,13 @@ Title.ascx + + create.aspx + ASPXCodeBehind + + + create.aspx + PartialViewMacro.ascx ASPXCodeBehind @@ -552,6 +559,7 @@ + @@ -2041,7 +2049,6 @@ - UserControl diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config index cb1e10a0ab..7dccba530d 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config @@ -86,7 +86,7 @@ false - + inline + + + ShowDuplicates @@ -143,7 +157,7 @@ true - + WebForms diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config index e636594221..473dbd8a42 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.config @@ -87,7 +87,21 @@ - throw - Throw an exception which can be caught by the global error handler defined in Application_OnError. If no such error handler is defined then you'll see the Yellow Screen Of Death (YSOD) error page. Note the error can also be handled by the umbraco.macro.Error event, where you can log/alarm with your own code and change the behaviour per event. --> - inline + inline + + + HideFileDuplicates diff --git a/src/Umbraco.Web.UI/umbraco/Create.aspx.cs b/src/Umbraco.Web.UI/umbraco/Create.aspx.cs new file mode 100644 index 0000000000..204285f180 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/Create.aspx.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Xml; +using Umbraco.Core; +using Umbraco.Core.IO; +using umbraco.cms.presentation.Trees; + +namespace Umbraco.Web.UI.Umbraco +{ + public partial class CreateDialog : global::umbraco.cms.presentation.Create + { + + //protected override void OnLoad(EventArgs e) + //{ + // if (SecurityCheck(Request.QueryString["nodeType"])) + // { + // //if we're allowed, then continue + // base.OnLoad(e); + // } + // else + // { + // //otherwise show an error + // UI.Visible = false; + // AccessError.Visible = true; + // } + //} + + //private bool SecurityCheck(string treeAlias) + //{ + // var tree = TreeDefinitionCollection.Instance.FindTree(treeAlias); + // if (tree != null) + // { + // //does the current user have access to the current app? + // var user = this.getUser(); + // var userApps = user.Applications; + // return userApps.Any(x => x.alias.InvariantEquals(tree.App.alias)); + // } + // return false; + //} + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs b/src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs new file mode 100644 index 0000000000..1e11eaf00d --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/Create.aspx.designer.cs @@ -0,0 +1,25 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Umbraco.Web.UI.Umbraco { + + + public partial class CreateDialog + { + + /// + /// AccessError control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.PlaceHolder AccessError; + } +} diff --git a/src/Umbraco.Web.UI/umbraco/create.aspx b/src/Umbraco.Web.UI/umbraco/create.aspx index 8bcc0cacb9..2b112f516b 100644 --- a/src/Umbraco.Web.UI/umbraco/create.aspx +++ b/src/Umbraco.Web.UI/umbraco/create.aspx @@ -1,4 +1,4 @@ -<%@ Page Language="c#" MasterPageFile="masterpages/umbracoDialog.Master" Codebehind="create.aspx.cs" AutoEventWireup="True" Inherits="umbraco.cms.presentation.Create" %> +<%@ Page Language="c#" MasterPageFile="masterpages/umbracoDialog.Master" Codebehind="CreateDialog.aspx.cs" AutoEventWireup="True" Inherits="Umbraco.Web.UI.Umbraco.CreateDialog" %> <%@ Register Namespace="umbraco" TagPrefix="umb" Assembly="umbraco" %> @@ -18,6 +18,13 @@ + + + + The current user does not have access to create this type of object + + + diff --git a/src/Umbraco.Web.UI/umbraco_client/Application/HistoryManager.js b/src/Umbraco.Web.UI/umbraco_client/Application/HistoryManager.js index b1f44a8f46..bed8630cf5 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Application/HistoryManager.js +++ b/src/Umbraco.Web.UI/umbraco_client/Application/HistoryManager.js @@ -13,7 +13,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls"); function getHashFragment(frag) { //tests for xss and ensures only the first alphanumeric chars are matched var result = hashFragmentRegex.exec(frag); - if (result.length > 0) { + if (result != null && result.length > 0) { return result[0]; } return ""; diff --git a/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js b/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js index decbf15e43..01e5f6112f 100644 --- a/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js +++ b/src/Umbraco.Web.UI/umbraco_client/ui/jquery.dd.js @@ -97,24 +97,23 @@ var t = ""; var clsName = ""; var pH = ""; //addition html - if (options.useSprite != false) { - clsName = ' ' + options.useSprite + ' ' + currentOptOption.className; - } else { - arrow = $(currentOptOption).prop("title"); - var reg = new RegExp(/^\{.*\}$/); - var isJson = reg.test(arrow); - if (options.jsonTitle == true && isJson == true) { - if (arrow.length != 0) { - var obj = eval("[" + arrow + "]"); - img = (typeof obj[0].image == "undefined") ? "" : obj[0].image; - t = (typeof obj[0].title == "undefined") ? "" : obj[0].title; - pH = (typeof obj[0].postHTML == "undefined") ? "" : obj[0].postHTML; - arrow = (img.length == 0) ? "" : ' '; - }; - } else { - arrow = (arrow.length == 0) ? "" : ' '; + + clsName = ' ' + options.useSprite + ' ' + currentOptOption.className; + arrow = $(currentOptOption).prop("title"); + var reg = new RegExp(/^\{.*\}$/); + var isJson = reg.test(arrow); + if (options.jsonTitle == true && isJson == true) { + if (arrow.length != 0) { + var obj = eval("[" + arrow + "]"); + img = (typeof obj[0].image == "undefined") ? "" : obj[0].image; + t = (typeof obj[0].title == "undefined") ? "" : obj[0].title; + pH = (typeof obj[0].postHTML == "undefined") ? "" : obj[0].postHTML; + arrow = (img.length == 0) ? "" : ' '; }; + } else { + arrow = (arrow.length == 0) ? "" : ' '; }; + var sText = $(currentOptOption).text(); var sValue = $(currentOptOption).val(); var sEnabledClass = ($(currentOptOption).prop("disabled") == true) ? "disabled" : "enabled"; @@ -325,7 +324,7 @@ }; }); - } + } }); }; $("#" + childid).bind("mouseout", function (event) { setInsideWindow(false); $(document).unbind("keydown", d_onkeydown); actionSettings.keyboardAction = false; actionSettings.currentKey = null; }); @@ -385,7 +384,7 @@ //shift var currentSelected = $(obj).prop("id"); var currentIndex = a_array[currentSelected].index; - for (var i = Math.min(oldIndex, currentIndex); i <= Math.max(oldIndex, currentIndex); i++) { + for (var i = Math.min(oldIndex, currentIndex) ; i <= Math.max(oldIndex, currentIndex) ; i++) { $("#" + getByIndex(i).id).addClass(styles.selected); }; } else { @@ -621,7 +620,7 @@ if (has_handler('change') == true) { //alert(1); var currentSelected = a_array[$("#" + childid + " a.selected").prop("id")]; - if(currentSelected != undefined) { + if (currentSelected != undefined) { var currentSelectedValue = currentSelected.text; if ($.trim(oldSelectedValue) !== $.trim(currentSelectedValue) && oldSelectedValue !== "") { $("#" + elementid).trigger("change"); @@ -786,9 +785,9 @@ }; if ($("#" + childid).css("display") == "none") { var oldSelected = a_array[$("#" + childid + " a.selected").prop("id")]; - if(oldSelected != undefined) + if (oldSelected != undefined) oldSelectedValue = oldSelected.text; - + //keyboard action inputText = ""; oldHeight = $("#" + childid).height(); diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs index ea20f6bb04..b48d680918 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs @@ -334,7 +334,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { if (_previewContent == null) { - _previewContent = new PreviewContent(user, new Guid(global::umbraco.BusinessLogic.StateHelper.Cookies.Preview.GetValue()), true); + _previewContent = new PreviewContent(user, new Guid(StateHelper.Cookies.Preview.GetValue()), true); if (_previewContent.ValidPreviewSet) _previewContent.LoadPreviewset(); } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b1a2e67dbb..220ea707f1 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -466,7 +466,7 @@ ASPXCodeBehind - + ASPXCodeBehind @@ -1878,7 +1878,9 @@ ASPXCodeBehind - + + ASPXCodeBehind + diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index 96677f7e62..3fc7ebee42 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Services; using Umbraco.Core.CodeAnnotations; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; +using Umbraco.Web.Security; using umbraco; using umbraco.IO; using umbraco.presentation; @@ -314,7 +315,7 @@ namespace Umbraco.Web { get { - return UmbracoEnsuredPage.CurrentUser; + return WebSecurity.CurrentUser; } } @@ -335,7 +336,7 @@ namespace Umbraco.Web return StateHelper.Cookies.Preview.HasValue // has preview cookie && UmbracoUser != null // has user - && !currentUrl.StartsWith(Umbraco.Core.IO.IOHelper.ResolveUrl(Umbraco.Core.IO.SystemDirectories.Umbraco)); // is not in admin UI + && !currentUrl.StartsWith(Core.IO.IOHelper.ResolveUrl(Core.IO.SystemDirectories.Umbraco)); // is not in admin UI } private HttpRequestBase GetRequestFromContext() diff --git a/src/Umbraco.Web/WebServices/FolderBrowserService.cs b/src/Umbraco.Web/WebServices/FolderBrowserService.cs index 4a060f5c6b..63eb497e69 100644 --- a/src/Umbraco.Web/WebServices/FolderBrowserService.cs +++ b/src/Umbraco.Web/WebServices/FolderBrowserService.cs @@ -1,16 +1,14 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; -using System.Text; -using System.Web; using System.Web.Script.Serialization; using Umbraco.Core; +using Umbraco.Core.IO; +using Umbraco.Core.Models; using Umbraco.Web.Media.ThumbnailProviders; -using umbraco.BasePages; using umbraco.BusinessLogic; -using umbraco.IO; using umbraco.cms.businesslogic.Tags; -using umbraco.cms.businesslogic.media; using Umbraco.Web.BaseRest; namespace Umbraco.Web.WebServices @@ -23,7 +21,10 @@ namespace Umbraco.Web.WebServices [RestExtensionMethod(ReturnXml = false)] public static string GetChildren(int parentId) { - var parentMedia = new global::umbraco.cms.businesslogic.media.Media(parentId); + var service = ApplicationContext.Current.Services.EntityService; + var parentMedia = service.Get(parentId, UmbracoObjectTypes.Media); + var mediaPath = parentMedia == null ? parentId.ToString(CultureInfo.InvariantCulture) : parentMedia.Path; + var currentUser = User.GetCurrent(); var data = new List(); @@ -32,32 +33,27 @@ namespace Umbraco.Web.WebServices throw new UnauthorizedAccessException("You must be logged in to use this service"); // Check user is allowed to access selected media item - if(!("," + parentMedia.Path + ",").Contains("," + currentUser.StartMediaId + ",")) + if (!("," + mediaPath + ",").Contains("," + currentUser.StartMediaId + ",")) throw new UnauthorizedAccessException("You do not have access to this Media node"); // Get children and filter + var entities = service.GetChildren(parentId, UmbracoObjectTypes.Media); //TODO: Only fetch files, not containers - //TODO: Cache responses to speed up susequent searches - foreach (var child in parentMedia.Children) + foreach (UmbracoEntity entity in entities) { - var fileProp = child.getProperty(Constants.Conventions.Media.File) ?? - child.GenericProperties.FirstOrDefault(x => - x.PropertyType.DataTypeDefinition.DataType.Id == new Guid(Constants.PropertyEditors.UploadField)); - - var fileUrl = fileProp != null ? fileProp.Value.ToString() : ""; - var thumbUrl = ThumbnailProvidersResolver.Current.GetThumbnailUrl(fileUrl); + var thumbUrl = ThumbnailProvidersResolver.Current.GetThumbnailUrl(entity.UmbracoFile); var item = new { - Id = child.Id, - Path = child.Path, - Name = child.Text, - Tags = string.Join(",", Tag.GetTags(child.Id).Select(x => x.TagCaption)), - MediaTypeAlias = child.ContentType.Alias, - EditUrl = string.Format("editMedia.aspx?id={0}", child.Id), - FileUrl = fileUrl, + Id = entity.Id, + Path = entity.Path, + Name = entity.Name, + Tags = string.Join(",", Tag.GetTags(entity.Id).Select(x => x.TagCaption)), + MediaTypeAlias = entity.ContentTypeAlias, + EditUrl = string.Format("editMedia.aspx?id={0}", entity.Id), + FileUrl = entity.UmbracoFile, ThumbnailUrl = !string.IsNullOrEmpty(thumbUrl) ? thumbUrl - : IOHelper.ResolveUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + child.ContentType.Thumbnail) + : IOHelper.ResolveUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + entity.ContentTypeThumbnail) }; data.Add(item); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs index be85585f8e..ab25a34e13 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseMediaTree.cs @@ -1,26 +1,30 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; using umbraco.BasePages; using umbraco.BusinessLogic; using umbraco.BusinessLogic.Actions; -using umbraco.cms.businesslogic.media; -using umbraco.cms.businesslogic.property; using umbraco.interfaces; using Umbraco.Core; +using Media = umbraco.cms.businesslogic.media.Media; +using Property = umbraco.cms.businesslogic.property.Property; namespace umbraco.cms.presentation.Trees { public abstract class BaseMediaTree : BaseTree { + private DisposableTimer _timer; + private User _user; + public BaseMediaTree(string application) : base(application) { } - private User m_user; - /// /// Returns the current User. This ensures that we don't instantiate a new User object /// each time. @@ -29,11 +33,10 @@ namespace umbraco.cms.presentation.Trees { get { - return (m_user == null ? (m_user = UmbracoEnsuredPage.CurrentUser) : m_user); + return (_user == null ? (_user = UmbracoEnsuredPage.CurrentUser) : _user); } } - public override void RenderJS(ref StringBuilder Javascript) { if (!string.IsNullOrEmpty(this.FunctionToCall)) @@ -53,8 +56,81 @@ function openMedia(id) { } } + //Updated Render method for improved performance, but currently not usable because of backwards compatibility + //with the OnBeforeTreeRender/OnAfterTreeRender events, which sends an array for legacy Media items. + /*public override void Render(ref XmlTree tree) + { + _timer = DisposableTimer.Start(x => LogHelper.Debug("Media tree loaded" + " (took " + x + "ms)")); + + var service = base.Services.EntityService; + var entities = service.GetChildren(m_id, UmbracoObjectTypes.Media); + + var args = new TreeEventArgs(tree); + OnBeforeTreeRender(entities, args); + + foreach (UmbracoEntity entity in entities) + { + XmlTreeNode xNode = XmlTreeNode.Create(this); + xNode.NodeID = entity.Id.ToString(CultureInfo.InvariantCulture); + xNode.Text = entity.Name; + + xNode.HasChildren = entity.HasChildren; + xNode.Source = this.IsDialog ? GetTreeDialogUrl(entity.Id) : GetTreeServiceUrl(entity.Id); + + xNode.Icon = entity.ContentTypeIcon; + xNode.OpenIcon = entity.ContentTypeIcon; + + xNode.Menu = this.ShowContextMenu ? new List(new IAction[] { ActionRefresh.Instance }) : null; + + if (IsDialog == false) + { + xNode.Action = "javascript:openMedia(" + entity.Id + ");"; + } + else + { + if (this.DialogMode == TreeDialogModes.fulllink) + { + if (string.IsNullOrEmpty(entity.UmbracoFile) == false) + { + xNode.Action = "javascript:openMedia('" + entity.UmbracoFile + "');"; + } + else + { + if (string.Equals(entity.ContentTypeAlias, Constants.Conventions.MediaTypes.Folder, StringComparison.OrdinalIgnoreCase)) + { + xNode.Action = "javascript:jQuery('.umbTree #" + entity.Id.ToString(CultureInfo.InvariantCulture) + "').click();"; + } + else + { + xNode.Action = null; + xNode.Style.DimNode(); + } + } + } + else + { + xNode.Action = "javascript:openMedia('" + entity.Id.ToString(CultureInfo.InvariantCulture) + "');"; + } + } + + OnBeforeNodeRender(ref tree, ref xNode, EventArgs.Empty); + if (xNode != null) + { + tree.Add(xNode); + OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty); + } + } + + //stop the timer and log the output + _timer.Dispose(); + + OnAfterTreeRender(entities, args); + }*/ + public override void Render(ref XmlTree tree) { + //_timer = DisposableTimer.Start(x => LogHelper.Debug("Media tree loaded" + " (took " + x + "ms)")); + Media[] docs = new Media(m_id).Children; var args = new TreeEventArgs(tree); @@ -124,10 +200,11 @@ function openMedia(id) { OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty); } } + //_timer.Dispose(); OnAfterTreeRender(docs, args); } - /// + /// /// Returns the value for a link in WYSIWYG mode, by default only media items that have a /// DataTypeUploadField are linkable, however, a custom tree can be created which overrides /// this method, or another GUID for a custom data type can be added to the LinkableMediaDataTypes diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMedia.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMedia.cs index 90135d9d15..80a1e4d307 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMedia.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadMedia.cs @@ -1,28 +1,9 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Text; -using System.Web; -using System.Xml; -using System.Configuration; using umbraco.BasePages; -using umbraco.BusinessLogic; using umbraco.businesslogic; -using umbraco.cms.businesslogic; -using umbraco.cms.businesslogic.cache; -using umbraco.cms.businesslogic.contentitem; -using umbraco.cms.businesslogic.datatype; -using umbraco.cms.businesslogic.language; -using umbraco.cms.businesslogic.media; -using umbraco.cms.businesslogic.member; -using umbraco.cms.businesslogic.property; -using umbraco.cms.businesslogic.web; using umbraco.interfaces; -using umbraco.DataLayer; using umbraco.BusinessLogic.Actions; -using umbraco.BusinessLogic.Utils; using umbraco.cms.presentation.Trees; using Umbraco.Core; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 49514c4fa9..2c66479ad7 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -17,7 +17,7 @@ using umbraco.cms.businesslogic.propertytype; using umbraco.cms.businesslogic.web; using umbraco.cms.helpers; using umbraco.controls.GenericProperties; -using umbraco.IO; +using Umbraco.Core.IO; using umbraco.presentation; using umbraco.BasePages; using ContentType = umbraco.cms.businesslogic.ContentType; @@ -43,7 +43,7 @@ namespace umbraco.controls // "Tab" tab protected uicontrols.Pane Pane8; - + // "Structure" tab protected DualSelectbox DualAllowedContentTypes = new DualSelectbox(); @@ -52,7 +52,7 @@ namespace umbraco.controls // "Generic properties" tab public uicontrols.TabPage GenericPropertiesTabPage; - + public GenericPropertyWrapper gp; private DataTable _dataTypeTable; private ArrayList _genericProperties = new ArrayList(); @@ -119,7 +119,7 @@ namespace umbraco.controls var ea = new SaveClickEventArgs("Saved"); ea.IconType = BasePage.speechBubbleIcon.success; - + //NOTE The saving of the 5 properties (Name, Alias, Icon, Description and Thumbnail) are divided //to avoid the multiple cache flushing when each property is set using the legacy ContentType class, //which has been reduced to the else-clause. @@ -135,7 +135,7 @@ namespace umbraco.controls int i = 0; var ids = SaveAllowedChildTypes(); - _contentType.ContentTypeItem.AllowedContentTypes = ids.Select(x => new ContentTypeSort{ Id = new Lazy(() => x), SortOrder = i++ }); + _contentType.ContentTypeItem.AllowedContentTypes = ids.Select(x => new ContentTypeSort { Id = new Lazy(() => x), SortOrder = i++ }); var tabs = SaveTabs(); foreach (var tab in tabs) @@ -146,7 +146,7 @@ namespace umbraco.controls } else { - _contentType.ContentTypeItem.PropertyGroups.Add(new PropertyGroup{ Id = tab.Item1, Name = tab.Item2, SortOrder = tab.Item3 }); + _contentType.ContentTypeItem.PropertyGroups.Add(new PropertyGroup { Id = tab.Item1, Name = tab.Item2, SortOrder = tab.Item3 }); } } @@ -244,7 +244,7 @@ namespace umbraco.controls } #region "Info" Pane - + private void SetupInfoPane() { InfoTabPage = TabView1.NewTabPage("Info"); @@ -253,43 +253,62 @@ namespace umbraco.controls InfoTabPage.Style.Add("text-align", "center"); ImageButton Save = InfoTabPage.Menu.NewImageButton(); - Save.Click += new System.Web.UI.ImageClickEventHandler(save_click); + Save.Click += save_click; Save.ImageUrl = UmbracoPath + "/images/editor/save.gif"; Save.AlternateText = ui.Text("save"); Save.ID = "save"; - var listOfIcons = new List(); - // Get icons - // nh css file update, add support for css sprites - foreach (string iconClass in cms.businesslogic.CMSNode.DefaultIconClasses) - { - var liText = iconClass - .Substring(1) - .SplitPascalCasing().ToFirstUpperInvariant() - .Replace("Spr Tree", "") - .Trim(); - ListItem li = new ListItem(liText, iconClass); - li.Attributes.Add("class", "spriteBackground sprTree " + iconClass.Trim('.')); - li.Attributes.Add("style", "padding-left:20px !important; background-repeat:no-repeat;"); + + var dirInfo = new DirectoryInfo(UmbracoContext.Current.Server.MapPath(SystemDirectories.Umbraco + "/images/umbraco")); + var fileInfo = dirInfo.GetFiles(); - if (!this.Page.IsPostBack && li.Value == _contentType.IconUrl) li.Selected = true; - listOfIcons.Add(li); + var spriteFileNames = new List(); + foreach (var iconClass in cms.businesslogic.CMSNode.DefaultIconClasses) + spriteFileNames.Add(IconClassToIconFileName(iconClass)); + + var diskFileNames = new List(); + foreach (var file in fileInfo) + diskFileNames.Add(FileNameToIconFileName(file)); + + var listOfIcons = new List(); + + foreach (var iconClass in cms.businesslogic.CMSNode.DefaultIconClasses) + { + // .sprNew was never intended to be in the document type editor + if (iconClass.ToLowerInvariant() == ".sprNew".ToLowerInvariant()) + continue; + + if (_contentType.IconUrl == iconClass) + { + AddSpriteListItem(iconClass, listOfIcons); + continue; + } + + if (UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideSpriteDuplicates + && diskFileNames.Contains(IconClassToIconFileName(iconClass))) + continue; + + AddSpriteListItem(iconClass, listOfIcons); } - DirectoryInfo dirInfo = new DirectoryInfo(UmbracoContext.Current.Server.MapPath(SystemDirectories.Umbraco + "/images/umbraco")); - FileInfo[] fileInfo = dirInfo.GetFiles(); - for (int i = 0; i < fileInfo.Length; i++) + foreach (var file in fileInfo) { // NH: don't show the sprite file - if (fileInfo[i].Name != "sprites.png" && fileInfo[i].Name != "sprites_ie6.gif") - { - ListItem li = new ListItem(fileInfo[i].Name, fileInfo[i].Name); - li.Attributes.Add("title", this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/umbraco/" + fileInfo[i].Name)); + if (file.Name.ToLowerInvariant() == "sprites.png".ToLowerInvariant() || file.Name.ToLowerInvariant() == "sprites_ie6.gif".ToLowerInvariant()) + continue; - if (li.Value == _contentType.IconUrl) - li.Selected = true; - listOfIcons.Add(li); + var listItemValue = this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/umbraco/" + file.Name); + if (_contentType.IconUrl == listItemValue) + { + AddFileListItem(file.Name, listItemValue, listOfIcons); + continue; } + + if (UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideFileDuplicates + && spriteFileNames.Contains(FileNameToIconFileName(file))) + continue; + + AddFileListItem(file.Name, listItemValue, listOfIcons); } ddlIcons.Items.AddRange(listOfIcons.OrderBy(o => o.Text).ToArray()); @@ -297,11 +316,15 @@ namespace umbraco.controls // Get thumbnails dirInfo = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.Umbraco + "/images/thumbnails")); fileInfo = dirInfo.GetFiles(); - for (int i = 0; i < fileInfo.Length; i++) + + foreach (var file in fileInfo) { - ListItem li = new ListItem(fileInfo[i].Name); - li.Attributes.Add("title", this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + fileInfo[i].Name)); - if (!this.Page.IsPostBack && li.Value == _contentType.Thumbnail) li.Selected = true; + var li = new ListItem(file.Name); + li.Attributes.Add("title", this.ResolveClientUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + file.Name)); + + if (this.Page.IsPostBack == false && li.Value == _contentType.Thumbnail) + li.Selected = true; + ddlThumbnails.Items.Add(li); } @@ -317,9 +340,49 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); description.Text = _contentType.GetRawDescription(); } - + + private void AddSpriteListItem(string iconClass, ICollection listOfIcons) + { + var li = new ListItem( + helper.SpaceCamelCasing((iconClass.Substring(1, iconClass.Length - 1))) + .Replace("Spr Tree", "") + .Trim(), iconClass); + + li.Attributes.Add("class", "spriteBackground sprTree " + iconClass.Trim('.')); + li.Attributes.Add("style", "padding-left:24px !important; background-repeat:no-repeat; width:auto; height:auto;"); + + AddListItem(listOfIcons, li); + } + + private void AddFileListItem(string fileName, string listItemValue, ICollection listOfIcons) + { + var li = new ListItem(fileName, fileName); + + li.Attributes.Add("title", listItemValue); + + AddListItem(listOfIcons, li); + } + + private void AddListItem(ICollection listOfIcons, ListItem li) + { + if (this.Page.IsPostBack == false && li.Value == _contentType.IconUrl) + li.Selected = true; + + listOfIcons.Add(li); + } + + private static string IconClassToIconFileName(string iconClass) + { + return iconClass.Substring(1, iconClass.Length - 1).ToLowerInvariant().Replace("sprTree".ToLowerInvariant(), ""); + } + + private static string FileNameToIconFileName(FileInfo file) + { + return file.Name.Substring(0, file.Name.LastIndexOf(".", StringComparison.Ordinal)).ToLowerInvariant(); + } + #endregion - + #region "Structure" Pane private void SetupStructurePane() @@ -355,7 +418,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } DualAllowedContentTypes.Value = chosenContentTypeIDs; } - + allowAtRoot.Checked = _contentType.AllowAtRoot; } @@ -449,7 +512,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); foreach (cms.businesslogic.propertytype.PropertyType pt in propertyTypes) { //If the PropertyType doesn't belong on this ContentType skip it and continue to the next one - if(pt.ContentTypeId != _contentType.Id) continue; + if (pt.ContentTypeId != _contentType.Id) continue; var gpw = new GenericPropertyWrapper(); gpw.ID = "gpw_" + pt.Id; @@ -632,9 +695,9 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); //Loop through the _genericProperties ArrayList and update all existing PropertyTypes foreach (GenericPropertyWrapper gpw in _genericProperties) { - if(gpw.PropertyType == null) continue; + if (gpw.PropertyType == null) continue; - if(contentTypeItem.PropertyTypes == null || contentTypeItem.PropertyTypes.Any(x => x.Alias == gpw.PropertyType.Alias) == false) continue; + if (contentTypeItem.PropertyTypes == null || contentTypeItem.PropertyTypes.Any(x => x.Alias == gpw.PropertyType.Alias) == false) continue; var propertyType = contentTypeItem.PropertyTypes.First(x => x.Alias == gpw.PropertyType.Alias); if (propertyType == null) continue; @@ -776,7 +839,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { PropertyTypes.Controls.Add(new LiteralControl("No properties defined on this tab. Click on the \"add a new property\" link at the top to create a new property.")); } - + private bool DoesPropertyTypeAliasExist(GenericProperty gpData) { bool hasAlias = _contentType.getPropertyType(Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim())) != null; @@ -851,7 +914,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); LoadContentType(_contentType.Id); BindDataGenericProperties(true); } - + #endregion #region "Tab" Pane @@ -859,7 +922,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); private void SetupTabPane() { uicontrols.TabPage tp = TabView1.NewTabPage("Tabs"); - + pnlTab.Style.Add("text-align", "center"); tp.Controls.Add(pnlTab); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.cs index 664cceae90..3bfc65d285 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.cs @@ -11,34 +11,35 @@ using System.Web.UI.HtmlControls; using System.Xml.XPath; using System.Xml; -using umbraco.IO; +using Umbraco.Core.IO; namespace umbraco.cms.presentation { - /// - /// Summary description for create. - /// - public partial class Create : BasePages.UmbracoEnsuredPage + + public class Create : BasePages.UmbracoEnsuredPage { [Obsolete("This property is no longer used")] protected umbWindow createWindow; - protected System.Web.UI.WebControls.Label helpText; - protected System.Web.UI.WebControls.TextBox rename; - protected System.Web.UI.WebControls.Label Label1; - protected System.Web.UI.WebControls.ListBox nodeType; + protected Label helpText; + protected TextBox rename; + protected Label Label1; + protected ListBox nodeType; + protected PlaceHolder UI; - protected void Page_Load(object sender, System.EventArgs e) + protected override void OnLoad(EventArgs e) { - // Load create definitions - string nodeType = Request.QueryString["nodeType"]; + base.OnLoad(e); - XmlDocument createDef = new XmlDocument(); - XmlTextReader defReader = new XmlTextReader(IOHelper.MapPath(SystemFiles.CreateUiXml)); + // Load create definitions + var nodeType = Request.QueryString["nodeType"]; + + var createDef = new XmlDocument(); + var defReader = new XmlTextReader(IOHelper.MapPath(SystemFiles.CreateUiXml)); createDef.Load(defReader); defReader.Close(); // Find definition for current nodeType - XmlNode def = createDef.SelectSingleNode("//nodeType [@alias = '" + nodeType + "']"); + var def = createDef.SelectSingleNode("//nodeType [@alias = '" + nodeType + "']"); if (def == null) { throw new ArgumentException("The create dialog for \"" + nodeType + "\" does not match anything defined in the \"" + SystemFiles.CreateUiXml + "\". This could mean an incorrectly installed package or a corrupt UI file"); @@ -47,7 +48,7 @@ namespace umbraco.cms.presentation try { //headerTitle.Text = title.Text; - UI.Controls.Add(new UserControl().LoadControl(SystemDirectories.Umbraco + def.SelectSingleNode("./usercontrol").FirstChild.Value)); + UI.Controls.Add(LoadControl(SystemDirectories.Umbraco + def.SelectSingleNode("./usercontrol").FirstChild.Value)); } catch (Exception ex) { @@ -55,13 +56,6 @@ namespace umbraco.cms.presentation } } - /// - /// UI control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder UI; + } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/userTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/userTasks.cs index 5977cecb95..e169d1ee8e 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/userTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/userTasks.cs @@ -12,35 +12,19 @@ namespace umbraco { public class userTasks : interfaces.ITaskReturnUrl { - - private string _alias; - private int _parentID; - private int _typeID; - private int _userID; private string _returnUrl = ""; public int UserId { - set { _userID = value; } - } - public int TypeID - { - set { _typeID = value; } - get { return _typeID; } + set { } } + public int TypeID { get; set; } - public string Alias - { - set { _alias = value; } - get { return _alias; } - } - public int ParentID - { - set { _parentID = value; } - get { return _parentID; } - } + public string Alias { get; set; } + + public int ParentID { get; set; } public string ReturnUrl { @@ -54,11 +38,11 @@ namespace umbraco //BusinessLogic.User.MakeNew(Alias, Alias, "", BusinessLogic.UserType.GetUserType(1)); //return true; - MembershipCreateStatus status = MembershipCreateStatus.ProviderError; + var status = MembershipCreateStatus.ProviderError; try { // Password is auto-generated. They are they required to change the password by editing the user information. - MembershipUser u = Membership.Providers[UmbracoSettings.DefaultBackofficeProvider].CreateUser(Alias, + var u = Membership.Providers[UmbracoSettings.DefaultBackofficeProvider].CreateUser(Alias, Membership.GeneratePassword( Membership.Providers[UmbracoSettings.DefaultBackofficeProvider].MinRequiredPasswordLength, Membership.Providers[UmbracoSettings.DefaultBackofficeProvider].MinRequiredNonAlphanumericCharacters), @@ -70,23 +54,16 @@ namespace umbraco } catch (Exception ex) { - LogHelper.Error(String.Format("Failed to create the user. Error from provider: {0}", status.ToString()), ex); + LogHelper.Error(string.Format("Failed to create the user. Error from provider: {0}", status.ToString()), ex); return false; } } public bool Delete() { - BusinessLogic.User u = BusinessLogic.User.GetUser(ParentID); + var u = User.GetUser(ParentID); u.disable(); return true; } - - public userTasks() - { - // - // TODO: Add constructor logic here - // - } } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs index 18eccdaaf1..aec5421174 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs @@ -5,7 +5,7 @@ using System.Web.UI.HtmlControls; using System.Xml; using System.Xml.Linq; using Umbraco.Core; -using umbraco.IO; +using Umbraco.Core.IO; namespace umbraco.presentation.umbraco.dialogs { @@ -69,12 +69,10 @@ namespace umbraco.presentation.umbraco.dialogs private void import_Click(object sender, EventArgs e) { - /*XmlDocument xd = new XmlDocument(); - xd.Load(tempFile.Value); - cms.businesslogic.packager.Installer.ImportDocumentType(xd.DocumentElement, base.getUser(), true); - dtNameConfirm.Text = xd.DocumentElement.SelectSingleNode("/DocumentType/Info/Name").FirstChild.Value;*/ + var xd = new XmlDocument(); + xd.Load(tempFile.Value); - var element = XElement.Parse(tempFile.Value); + var element = XElement.Parse(xd.InnerXml); var importContentTypes = ApplicationContext.Current.Services.PackagingService.ImportContentTypes(element); var contentType = importContentTypes.FirstOrDefault(); if (contentType != null) @@ -85,25 +83,22 @@ namespace umbraco.presentation.umbraco.dialogs done.Visible = true; } - private void submit_Click(object sender, System.EventArgs e) + private void submit_Click(object sender, EventArgs e) { tempFileName = "justDelete_" + Guid.NewGuid().ToString() + ".udt"; - string fileName = IOHelper.MapPath(SystemDirectories.Data + "/" + tempFileName); + var fileName = IOHelper.MapPath(SystemDirectories.Data + "/" + tempFileName); tempFile.Value = fileName; documentTypeFile.PostedFile.SaveAs(fileName); - XmlDocument xd = new XmlDocument(); + var xd = new XmlDocument(); xd.Load(fileName); - dtName.Text = xd.DocumentElement.SelectSingleNode("/DocumentType/Info/Name").FirstChild.Value; - dtAlias.Text = xd.DocumentElement.SelectSingleNode("/DocumentType/Info/Alias").FirstChild.Value; - + dtName.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Name").FirstChild.Value; + dtAlias.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Alias").FirstChild.Value; Wizard.Visible = false; done.Visible = false; Confirm.Visible = true; - } - } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs index 54803dd96d..0c328e17a2 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs @@ -10,6 +10,7 @@ using System.Xml; using Umbraco.Core.Macros; using Umbraco.Web; using Umbraco.Web.PublishedCache; +using Umbraco.Web.PublishedCache.XmlPublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Templates; using umbraco.cms.businesslogic; @@ -91,49 +92,20 @@ namespace umbraco.presentation.templateControls /// A string of field contents (macros not parsed) protected virtual string GetFieldContents(Item item) { - string tempElementContent = String.Empty; + var tempElementContent = string.Empty; // if a nodeId is specified we should get the data from another page than the current one - if (!String.IsNullOrEmpty(item.NodeId)) + if (string.IsNullOrEmpty(item.NodeId) == false) { - int? tempNodeId = item.GetParsedNodeId(); + var tempNodeId = item.GetParsedNodeId(); if (tempNodeId != null && tempNodeId.Value != 0) { - //moved the following from the catch block up as this will allow fallback options alt text etc to work - - //get the publishedcontent item - var publishedContent = Umbraco.Web.UmbracoContext.Current.ContentCache.GetById(tempNodeId.Value); - - var itemPage = new page(publishedContent); - tempElementContent = new item(publishedContent, itemPage.Elements, item.LegacyAttributes).FieldContent; - - /*removed as would fail as there is a incorrect cast in the method called. - Also the following code does not respect any of Umbraco Items fallback and formatting options */ - - //string currentField = helper.FindAttribute(item.LegacyAttributes, "field"); - // check for a cached instance of the content - //object contents = GetContentFromCache(tempNodeId.Value, currentField); - //if (contents != null) - // tempElementContent = (string)contents; - //else - //{ - // // as the field can be used for both documents, media and even members we'll use the - // // content class to lookup field items - // try - // { - // tempElementContent = GetContentFromDatabase(item.LegacyAttributes, tempNodeId.Value, currentField); - // } - // catch - // { - // // content was not found in property fields, - // // so the last place to look for is page fields - // page itemPage = new page(content.Instance.XmlContent.GetElementById(tempNodeId.ToString())); - // tempElementContent = new item(itemPage.Elements, item.LegacyAttributes).FieldContent; - // } - //} + var xml = ((PublishedContentCache) PublishedContentCacheResolver.Current.ContentCache) + .GetXml(Umbraco.Web.UmbracoContext.Current); + var itemPage = new page(xml.GetElementById(tempNodeId.ToString())); + tempElementContent = new item(itemPage.Elements, item.LegacyAttributes).FieldContent; } - } else { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs index 5d03743666..2f4274fabb 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/codeEditorSave.asmx.cs @@ -62,7 +62,7 @@ namespace umbraco.presentation.webservices //deletes the old css file if the name was changed... - if (fileName != oldName) + if (fileName.ToLowerInvariant() != oldName.ToLowerInvariant()) { string p = IOHelper.MapPath(SystemDirectories.Css + "/" + oldName + ".css"); if (System.IO.File.Exists(p)) diff --git a/src/umbraco.businesslogic/UmbracoSettings.cs b/src/umbraco.businesslogic/UmbracoSettings.cs index c7db9fdeb1..1e206dcc16 100644 --- a/src/umbraco.businesslogic/UmbracoSettings.cs +++ b/src/umbraco.businesslogic/UmbracoSettings.cs @@ -562,6 +562,18 @@ namespace umbraco get { return Umbraco.Core.Configuration.UmbracoSettings.MacroErrorBehaviour; } } + /// + /// This configuration setting defines how to show icons in the document type editor. + /// - ShowDuplicates - Show duplicates in files and sprites. (default and current Umbraco 'normal' behaviour) + /// - HideSpriteDuplicates - Show files on disk and hide duplicates from the sprite + /// - HideFileDuplicates - Show files in the sprite and hide duplicates on disk + /// + /// MacroErrorBehaviour enum defining how to show icons in the document type editor. + public static IconPickerBehaviour IconPickerBehaviour + { + get { return Umbraco.Core.Configuration.UmbracoSettings.IconPickerBehaviour; } + } + /// /// Configuration regarding webservices /// diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 5df3ee944f..62161ad05a 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -99,7 +99,7 @@ namespace umbraco.cms.businesslogic /// Used for cache so we don't have to lookup column names all the time, this is actually only used for the ChildrenAsTable methods /// private static readonly ConcurrentDictionary> AliasToNames = new ConcurrentDictionary>(); - private static readonly ConcurrentDictionary, Guid> PropertyTypeCache = new ConcurrentDictionary, Guid>(); + private static readonly ConcurrentDictionary, Guid> PropertyTypeCache = new ConcurrentDictionary, Guid>(); /// /// Returns a content type's columns alias -> name mapping @@ -111,12 +111,12 @@ namespace umbraco.cms.businesslogic /// internal static IDictionary GetAliasesAndNames(string contentTypeAlias) { - return AliasToNames.GetOrAdd(contentTypeAlias, s => - { - var ct = ContentType.GetByAlias(contentTypeAlias); - var userFields = ct.PropertyTypes.ToDictionary(x => x.Alias, x => x.Name); - return userFields; - }); + return AliasToNames.GetOrAdd(contentTypeAlias, s => + { + var ct = GetByAlias(contentTypeAlias); + var userFields = ct.PropertyTypes.ToDictionary(x => x.Alias, x => x.Name); + return userFields; + }); } /// @@ -125,7 +125,7 @@ namespace umbraco.cms.businesslogic /// public static void RemoveFromDataTypeCache(string contentTypeAlias) { - var toDelete = PropertyTypeCache.Keys.Where(key => string.Equals(key.first, contentTypeAlias)).ToList(); + var toDelete = PropertyTypeCache.Keys.Where(key => string.Equals(key.Item1, contentTypeAlias)).ToList(); foreach (var key in toDelete) { Guid id; @@ -139,34 +139,31 @@ namespace umbraco.cms.businesslogic /// internal static void RemoveAllDataTypeCache() { - AliasToNames.Clear(); PropertyTypeCache.Clear(); } public static Guid GetDataType(string contentTypeAlias, string propertyTypeAlias) { - var key = new Tuple() - { - first = contentTypeAlias, - second = propertyTypeAlias - }; + var key = new System.Tuple(contentTypeAlias, propertyTypeAlias); - return PropertyTypeCache.GetOrAdd(key, tuple => - { - // With 4.10 we can't do this via direct SQL as we have content type mixins - var controlId = Guid.Empty; - var ct = GetByAlias(contentTypeAlias); + + return PropertyTypeCache.GetOrAdd( + key, + tuple => + { + // With 4.10 we can't do this via direct SQL as we have content type mixins + var controlId = Guid.Empty; + var ct = GetByAlias(contentTypeAlias); var pt = ct.getPropertyType(propertyTypeAlias); if (pt != null) { controlId = pt.DataTypeDefinition.DataType.Id; } - return controlId; + return controlId; }); } - /// /// Gets the type of the content. /// @@ -175,7 +172,7 @@ namespace umbraco.cms.businesslogic public static ContentType GetContentType(int id) { return ApplicationContext.Current.ApplicationCache.GetCacheItem - (string.Format("UmbracoContentType{0}", id.ToString()), + (string.Format("UmbracoContentType{0}", id), TimeSpan.FromMinutes(30), () => new ContentType(id)); } @@ -228,24 +225,22 @@ namespace umbraco.cms.businesslogic object tmp = SqlHelper.ExecuteScalar("Select propertyTypeGroupId from cmsPropertyType where id = " + pt.Id.ToString()); if (tmp == DBNull.Value) return 0; - else return int.Parse(tmp.ToString()); + return int.Parse(tmp.ToString()); } #endregion #region Private Members - //private bool _optimizedMode = false; private bool _allowAtRoot; private string _alias; private string _iconurl; private string _description; private string _thumbnail; List m_masterContentTypes; - private bool _isContainerContentType = false; - - private List m_AllowedChildContentTypeIDs = null; - private List m_VirtualTabs = null; + private bool _isContainerContentType; + private List _allowedChildContentTypeIDs; + private List _virtualTabs; protected internal IContentTypeComposition ContentTypeItem; @@ -380,17 +375,14 @@ namespace umbraco.cms.businesslogic { if (!_description.StartsWith("#")) return _description; - else + var lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); + if (lang != null) { - Language lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); - if (lang != null) + if (Dictionary.DictionaryItem.hasKey(_description.Substring(1, _description.Length - 1))) { - if (Dictionary.DictionaryItem.hasKey(_description.Substring(1, _description.Length - 1))) - { - var di = - new Dictionary.DictionaryItem(_description.Substring(1, _description.Length - 1)); - return di.Value(lang.id); - } + var di = + new Dictionary.DictionaryItem(_description.Substring(1, _description.Length - 1)); + return di.Value(lang.id); } } @@ -450,6 +442,7 @@ namespace umbraco.cms.businesslogic } } + /// /// Human readable name/label /// @@ -458,25 +451,20 @@ namespace umbraco.cms.businesslogic { get { - string tempText = base.Text; + var tempText = base.Text; if (!tempText.StartsWith("#")) return tempText; - else + var lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); + if (lang != null) { - Language lang = - Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); - if (lang != null) + if (Dictionary.DictionaryItem.hasKey(tempText.Substring(1, tempText.Length - 1))) { - if (Dictionary.DictionaryItem.hasKey(tempText.Substring(1, tempText.Length - 1))) - { - Dictionary.DictionaryItem di = - new Dictionary.DictionaryItem(tempText.Substring(1, tempText.Length - 1)); - return di.Value(lang.id); - } + var di = new Dictionary.DictionaryItem(tempText.Substring(1, tempText.Length - 1)); + return di.Value(lang.id); } - - return "[" + tempText + "]"; } + + return "[" + tempText + "]"; } set { @@ -536,8 +524,8 @@ namespace umbraco.cms.businesslogic { foreach (var mct in MasterContentTypes) { - var pts = ContentType.GetContentType(mct).PropertyTypes; - foreach (PropertyType pt in pts) + var pts = GetContentType(mct).PropertyTypes; + foreach (var pt in pts) { if (result.ContainsKey(pt.Id) == false) result.Add(pt.Id, pt); @@ -715,7 +703,7 @@ namespace umbraco.cms.businesslogic get { EnsureVirtualTabs(); - return m_VirtualTabs.ToArray(); + return _virtualTabs.ToArray(); } } @@ -727,10 +715,11 @@ namespace umbraco.cms.businesslogic public void ClearVirtualTabs() { //NOTE: SD: There is no cache to clear so this doesn't actually do anything - foreach (TabI t in getVirtualTabs) + //NOTE: SD: There is no cache to clear so this doesn't actually do anything + foreach (var t in getVirtualTabs) Tab.FlushCache(t.Id, Id); - m_VirtualTabs = null; + _virtualTabs = null; } /// @@ -742,25 +731,23 @@ namespace umbraco.cms.businesslogic get { //optimize this property so it lazy loads the data only one time. - if (m_AllowedChildContentTypeIDs == null) + if (_allowedChildContentTypeIDs == null) { - m_AllowedChildContentTypeIDs = new List(); - using (IRecordsReader dr = SqlHelper.ExecuteReader( - "Select AllowedId from cmsContentTypeAllowedContentType where id=" + - Id)) + _allowedChildContentTypeIDs = new List(); + using (var dr = SqlHelper.ExecuteReader("Select AllowedId from cmsContentTypeAllowedContentType where id=" + Id)) { while (dr.Read()) { - m_AllowedChildContentTypeIDs.Add(dr.GetInt("AllowedId")); + _allowedChildContentTypeIDs.Add(dr.GetInt("AllowedId")); } } } - return m_AllowedChildContentTypeIDs.ToArray(); + return _allowedChildContentTypeIDs.ToArray(); } set { - m_AllowedChildContentTypeIDs = value.ToList(); + _allowedChildContentTypeIDs = value.ToList(); //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. @@ -822,13 +809,13 @@ namespace umbraco.cms.businesslogic { var contentTypes = new List(); - using (IRecordsReader dr = - SqlHelper.ExecuteReader(m_SQLOptimizedGetAll.Trim(), SqlHelper.CreateParameter("@nodeObjectType", base.nodeObjectType))) + using (var dr = + SqlHelper.ExecuteReader(m_SQLOptimizedGetAll.Trim(), SqlHelper.CreateParameter("@nodeObjectType", nodeObjectType))) { while (dr.Read()) { //create the ContentType object without setting up - ContentType ct = new ContentType(dr.Get("id"), true); + var ct = new ContentType(dr.Get("id"), true); //populate it's CMSNode properties ct.PopulateCMSNodeFromReader(dr); //populate it's ContentType properties @@ -853,10 +840,10 @@ namespace umbraco.cms.businesslogic PropertyType pt = PropertyType.MakeNew(dt, this, Name, Alias); // Optimized call - populatePropertyData(pt, this.Id); + PopulatePropertyData(pt, Id); // Inherited content types (document types only) - populateMasterContentTypes(pt, this.Id); + PopulateMasterContentTypes(pt, Id); // foreach (Content c in Content.getContentOfContentType(this)) // c.addProperty(pt,c.Version); @@ -952,7 +939,7 @@ namespace umbraco.cms.businesslogic /// Updates the sort order of the Tab /// /// The Id of the Tab to be updated - /// The new order number + /// The new order number [Obsolete("Use PropertyTypeGroup methods instead", false)] public void SetTabSortOrder(int tabId, int sortOrder) { @@ -972,18 +959,14 @@ namespace umbraco.cms.businesslogic public PropertyType getPropertyType(string alias) { // NH 22-08-08, Get from the property type stack to ensure support of master document types - object o = this.PropertyTypes.Find(pt => pt.Alias == alias); + object o = PropertyTypes.Find(pt => pt.Alias == alias); if (o == null) { return null; } - else - { - return (PropertyType)o; - } + return (PropertyType)o; } - /// /// Deletes the current ContentType /// @@ -993,9 +976,9 @@ namespace umbraco.cms.businesslogic FlushFromCache(Id); // Delete all propertyTypes - foreach (PropertyType pt in PropertyTypes) + foreach (var pt in PropertyTypes) { - if (pt.ContentTypeId == this.Id) + if (pt.ContentTypeId == Id) { pt.delete(); } @@ -1080,8 +1063,7 @@ namespace umbraco.cms.businesslogic } // TODO: Load master content types - using (IRecordsReader dr = - SqlHelper.ExecuteReader("Select allowAtRoot, isContainer, Alias,icon,thumbnail,description from cmsContentType where nodeid=" + Id) + using (var dr = SqlHelper.ExecuteReader("Select allowAtRoot, isContainer, Alias,icon,thumbnail,description from cmsContentType where nodeid=" + Id) ) { if (dr.Read()) @@ -1100,7 +1082,7 @@ namespace umbraco.cms.businesslogic /// /// The id. public static void FlushFromCache(int id) - { + { //Ensure that MediaTypes are reloaded from db by clearing cache InMemoryCacheProvider.Current.Clear(); @@ -1134,7 +1116,6 @@ namespace umbraco.cms.businesslogic ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.ContentTypePropertiesCacheKey); RemoveAllDataTypeCache(); - ClearVirtualTabs(); } @@ -1163,12 +1144,12 @@ namespace umbraco.cms.businesslogic // If that happens, the m_VirtualTabs will contain duplicates. // We must prevent two threads from running InitializeVirtualTabs at the same time. // We must also prevent m_VirtualTabs from being modified while it is being populated. - if (m_VirtualTabs == null || m_VirtualTabs.Count == 0) + if (_virtualTabs == null || _virtualTabs.Count == 0) { lock (_virtualTabLoadLock) { //optimize, lazy load the data only one time - if (m_VirtualTabs == null || m_VirtualTabs.Count == 0) + if (_virtualTabs == null || _virtualTabs.Count == 0) { InitializeVirtualTabs(); } @@ -1200,23 +1181,23 @@ namespace umbraco.cms.businesslogic temporaryList.Sort((a, b) => a.SortOrder.CompareTo(b.SortOrder)); // now that we aren't going to modify the list, we can set it to the class-scoped variable. - m_VirtualTabs = temporaryList.DistinctBy(x => x.Id).ToList(); + _virtualTabs = temporaryList.DistinctBy(x => x.Id).ToList(); } - private void populateMasterContentTypes(PropertyType pt, int docTypeId) + private static void PopulateMasterContentTypes(PropertyType pt, int docTypeId) { - foreach (web.DocumentType docType in web.DocumentType.GetAllAsList()) + foreach (var docType in DocumentType.GetAllAsList()) { //TODO: Check for multiple references (mixins) not causing endless loops! if (docType.MasterContentTypes.Contains(docTypeId)) { - populatePropertyData(pt, docType.Id); - populateMasterContentTypes(pt, docType.Id); + PopulatePropertyData(pt, docType.Id); + PopulateMasterContentTypes(pt, docType.Id); } } } - private void populatePropertyData(PropertyType pt, int contentTypeId) + private static void PopulatePropertyData(PropertyType pt, int contentTypeId) { // NH: PropertyTypeId inserted directly into SQL instead of as a parameter for SQL CE 4 compatibility SqlHelper.ExecuteNonQuery( @@ -1389,7 +1370,7 @@ namespace umbraco.cms.businesslogic [Obsolete("Please use GetPropertyTypes() instead", false)] public PropertyType[] PropertyTypes { - get { return GetPropertyTypes(this.ContentType, true); } + get { return GetPropertyTypes(ContentType, true); } } @@ -1429,17 +1410,12 @@ namespace umbraco.cms.businesslogic var tempCaption = SqlHelper.ExecuteScalar("Select text from cmsPropertyTypeGroup where id = " + id.ToString()); if (!tempCaption.StartsWith("#")) return tempCaption; - else + var lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); + if (lang != null) { - Language lang = - Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); - if (lang != null) - return - new Dictionary.DictionaryItem(tempCaption.Substring(1, tempCaption.Length - 1)).Value( - lang.id); - else - return "[" + tempCaption + "]"; + return new Dictionary.DictionaryItem(tempCaption.Substring(1, tempCaption.Length - 1)).Value(lang.id); } + return "[" + tempCaption + "]"; } catch { @@ -1447,9 +1423,9 @@ namespace umbraco.cms.businesslogic } } - private int _id; + private readonly int _id; - private int? _sortOrder = null; + private int? _sortOrder; /// /// The sortorder of the tab @@ -1482,10 +1458,10 @@ namespace umbraco.cms.businesslogic // hence moving it up. if (SortOrder > 0) { - int newsortorder = SortOrder - 1; + var newsortorder = SortOrder - 1; // Find the tab to switch with - TabI[] Tabs = _contenttype.getVirtualTabs; - foreach (Tab t in Tabs) + var tabs = _contenttype.getVirtualTabs; + foreach (Tab t in tabs) { if (t.SortOrder == newsortorder) t.SortOrder = SortOrder; @@ -1503,12 +1479,12 @@ namespace umbraco.cms.businesslogic FixTabOrder(); // If this tab is not the last tab we can switch places with the next tab // hence moving it down. - TabI[] Tabs = _contenttype.getVirtualTabs; - if (SortOrder < Tabs.Length - 1) + var tabs = _contenttype.getVirtualTabs; + if (SortOrder < tabs.Length - 1) { - int newsortorder = SortOrder + 1; + var newsortorder = SortOrder + 1; // Find the tab to switch with - foreach (Tab t in Tabs) + foreach (Tab t in tabs) { if (t.SortOrder == newsortorder) t.SortOrder = SortOrder; @@ -1534,10 +1510,10 @@ namespace umbraco.cms.businesslogic /// private void FixTabOrder() { - TabI[] Tabs = _contenttype.getVirtualTabs; - for (int i = 0; i < Tabs.Length; i++) + var tabs = _contenttype.getVirtualTabs; + for (int i = 0; i < tabs.Length; i++) { - Tab t = (Tab)Tabs[i]; + var t = (Tab)tabs[i]; t.SortOrder = i; } } @@ -1572,23 +1548,18 @@ namespace umbraco.cms.businesslogic { if (!_caption.StartsWith("#")) return _caption; - else + + var lang = Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); + if (lang != null) { - Language lang = - Language.GetByCultureCode(Thread.CurrentThread.CurrentCulture.Name); - if (lang != null) + if (Dictionary.DictionaryItem.hasKey(_caption.Substring(1, _caption.Length - 1))) { - if (Dictionary.DictionaryItem.hasKey(_caption.Substring(1, _caption.Length - 1))) - { - var di = - new Dictionary.DictionaryItem(_caption.Substring(1, _caption.Length - 1)); - if (di != null) - return di.Value(lang.id); - } + var di = new Dictionary.DictionaryItem(_caption.Substring(1, _caption.Length - 1)); + return di.Value(lang.id); } - - return "[" + _caption + "]"; } + + return "[" + _caption + "]"; } } } diff --git a/src/umbraco.cms/businesslogic/language/Language.cs b/src/umbraco.cms/businesslogic/language/Language.cs index 55c010d655..0618b9d7d4 100644 --- a/src/umbraco.cms/businesslogic/language/Language.cs +++ b/src/umbraco.cms/businesslogic/language/Language.cs @@ -6,11 +6,9 @@ using System.Xml; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Logging; -using umbraco.cms.businesslogic.cache; using umbraco.DataLayer; using umbraco.BusinessLogic; using System.Linq; -using System.Runtime.CompilerServices; namespace umbraco.cms.businesslogic.language { @@ -56,9 +54,7 @@ namespace umbraco.cms.businesslogic.language /// The id. public Language(int id) { - var lang = GetAllAsList() - .Where(x => x.id == id) - .SingleOrDefault(); + var lang = GetAllAsList().SingleOrDefault(x => x.id == id); if (lang == null) { throw new ArgumentException("No language found with the specified id"); @@ -184,16 +180,13 @@ namespace umbraco.cms.businesslogic.language /// public static Language Import(XmlNode xmlData) { - string cA = xmlData.Attributes["CultureAlias"].Value; + var cA = xmlData.Attributes["CultureAlias"].Value; if (GetByCultureCode(cA) == null) { MakeNew(cA); return GetByCultureCode(cA); } - else - { - return null; - } + return null; } #endregion @@ -282,10 +275,6 @@ namespace umbraco.cms.businesslogic.language /// public void Delete() { - //if (this.id == DefaultLanguageId) - //{ - // throw new InvalidOperationException("You cannot delete the default language: en-US"); - //} lock (Locker) { if (SqlHelper.ExecuteScalar("SELECT count(id) FROM umbracoDomains where domainDefaultLanguage = @id", @@ -322,10 +311,10 @@ namespace umbraco.cms.businesslogic.language /// public XmlNode ToXml(XmlDocument xd) { - XmlNode language = xd.CreateElement("Language"); - language.Attributes.Append(xmlHelper.addAttribute(xd, "Id", this.id.ToString())); - language.Attributes.Append(xmlHelper.addAttribute(xd, "CultureAlias", this.CultureAlias)); - language.Attributes.Append(xmlHelper.addAttribute(xd, "FriendlyName", this.FriendlyName)); + var language = xd.CreateElement("Language"); + language.Attributes.Append(XmlHelper.AddAttribute(xd, "Id", id.ToString())); + language.Attributes.Append(XmlHelper.AddAttribute(xd, "CultureAlias", CultureAlias)); + language.Attributes.Append(XmlHelper.AddAttribute(xd, "FriendlyName", FriendlyName)); return language; }
+ The current user does not have access to create this type of object +