diff --git a/build/UmbracoVersion.txt b/build/UmbracoVersion.txt index 469bf7a466..df03fe8381 100644 --- a/build/UmbracoVersion.txt +++ b/build/UmbracoVersion.txt @@ -1,2 +1,2 @@ # Usage: on line 2 put the release version, on line 3 put the version comment (example: beta) -7.5.4 \ No newline at end of file +7.5.5 \ No newline at end of file diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 39cbd18c2a..b3b5633864 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -11,5 +11,5 @@ using System.Resources; [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("7.5.4")] -[assembly: AssemblyInformationalVersion("7.5.4")] \ No newline at end of file +[assembly: AssemblyFileVersion("7.5.5")] +[assembly: AssemblyInformationalVersion("7.5.5")] \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index ddde8fbd5f..ccf4aecf13 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration { public class UmbracoVersion { - private static readonly Version Version = new Version("7.5.4"); + private static readonly Version Version = new Version("7.5.5"); /// /// Gets the current version of Umbraco. diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs index 7e2bb88964..d7f4576137 100644 --- a/src/Umbraco.Core/Constants-Conventions.cs +++ b/src/Umbraco.Core/Constants-Conventions.cs @@ -122,6 +122,11 @@ namespace Umbraco.Core /// MediaType alias for an image. /// public const string Image = "Image"; + + /// + /// MediaType alias indicating allowing auto-selection. + /// + public const string AutoSelect = "umbracoAutoSelect"; } /// diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index 9570024b09..8b33599436 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -149,8 +149,8 @@ namespace Umbraco.Core.Persistence.Migrations.Initial private void CreateCmsContentTypeData() { _database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 532, NodeId = 1031, Alias = Constants.Conventions.MediaTypes.Folder, Icon = "icon-folder", Thumbnail = "icon-folder", IsContainer = false, AllowAtRoot = true }); - _database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 533, NodeId = 1032, Alias = Constants.Conventions.MediaTypes.Image, Icon = "icon-picture", Thumbnail = "icon-picture" }); - _database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 534, NodeId = 1033, Alias = Constants.Conventions.MediaTypes.File, Icon = "icon-document", Thumbnail = "icon-document" }); + _database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 533, NodeId = 1032, Alias = Constants.Conventions.MediaTypes.Image, Icon = "icon-picture", Thumbnail = "icon-picture", AllowAtRoot = true }); + _database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 534, NodeId = 1033, Alias = Constants.Conventions.MediaTypes.File, Icon = "icon-document", Thumbnail = "icon-document", AllowAtRoot = true }); _database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 531, NodeId = 1044, Alias = Constants.Conventions.MemberTypes.DefaultAlias, Icon = "icon-user", Thumbnail = "icon-user" }); } diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveFive/UpdateAllowedMediaTypesAtRoot.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveFive/UpdateAllowedMediaTypesAtRoot.cs new file mode 100644 index 0000000000..c9a0d509e6 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveFive/UpdateAllowedMediaTypesAtRoot.cs @@ -0,0 +1,25 @@ +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveFive +{ + /// + /// See: http://issues.umbraco.org/issue/U4-4196 + /// + [Migration("7.5.5", 1, GlobalSettings.UmbracoMigrationName)] + public class UpdateAllowedMediaTypesAtRoot : MigrationBase + { + public UpdateAllowedMediaTypesAtRoot(ISqlSyntaxProvider sqlSyntax, ILogger logger) + : base(sqlSyntax, logger) + { } + + public override void Up() + { + Execute.Sql("UPDATE cmsContentType SET allowAtRoot = 1 WHERE nodeId = 1032 OR nodeId = 1033"); + } + + public override void Down() + { } + } +} diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs index 907f9b62c5..64989f9269 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaRepository.cs @@ -38,5 +38,15 @@ namespace Umbraco.Core.Persistence.Repositories /// An Enumerable list of objects IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, bool orderBySystemField, string filter = ""); + + /// + /// Gets paged media descendants as XML by path + /// + /// Path starts with + /// Page number + /// Page size + /// Total records the query would return without paging + /// A paged enumerable of XML entries of media items + IEnumerable GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, out long totalRecords); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs index 598c9e912d..7a6fa4c34e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs @@ -465,6 +465,30 @@ namespace Umbraco.Core.Persistence.Repositories } + /// + /// Gets paged media descendants as XML by path + /// + /// Path starts with + /// Page number + /// Page size + /// Total records the query would return without paging + /// A paged enumerable of XML entries of media items + public IEnumerable GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, out long totalRecords) + { + Sql query; + if (path == "-1") + { + query = new Sql().Select("nodeId, xml").From("cmsContentXml").Where("nodeId IN (SELECT id FROM umbracoNode WHERE nodeObjectType = @0)", Guid.Parse(Constants.ObjectTypes.Media)).OrderBy("nodeId"); + } + else + { + query = new Sql().Select("nodeId, xml").From("cmsContentXml").Where("nodeId IN (SELECT id FROM umbracoNode WHERE path LIKE @0)", path.EnsureEndsWith(",%")).OrderBy("nodeId"); + } + var pagedResult = Database.Page(pageIndex+1, pageSize, query); + totalRecords = pagedResult.TotalItems; + return pagedResult.Items.Select(dto => XElement.Parse(dto.Xml)); + } + private IEnumerable ProcessQuery(Sql sql) { //NOTE: This doesn't allow properties to be part of the query diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs index 6ff8f75402..d25ddf7f58 100644 --- a/src/Umbraco.Core/Services/IMediaService.cs +++ b/src/Umbraco.Core/Services/IMediaService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Xml.Linq; using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.Persistence.DatabaseModelDefinitions; @@ -57,6 +58,19 @@ namespace Umbraco.Core.Services /// public interface IMediaService : IService { + /// + /// Gets all XML entries found in the cmsContentXml table based on the given path + /// + /// Path starts with + /// Page number + /// Page size + /// Total records the query would return without paging + /// A paged enumerable of XML entries of media items + /// + /// If -1 is passed, then this will return all media xml entries, otherwise will return all descendents from the path + /// + IEnumerable GetPagedXmlEntries(string path, long pageIndex, int pageSize, out long totalRecords); + /// /// Rebuilds all xml content in the cmsContentXml table for all media /// diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index 29235cc7ab..a1182ce80a 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -1199,6 +1199,27 @@ namespace Umbraco.Core.Services return true; } + /// + /// Gets paged media descendants as XML by path + /// + /// Path starts with + /// Page number + /// Page size + /// Total records the query would return without paging + /// A paged enumerable of XML entries of media items + public IEnumerable GetPagedXmlEntries(string path, long pageIndex, int pageSize, out long totalRecords) + { + Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); + Mandate.ParameterCondition(pageSize > 0, "pageSize"); + + var uow = UowProvider.GetUnitOfWork(); + using (var repository = RepositoryFactory.CreateMediaRepository(uow)) + { + var contents = repository.GetPagedXmlEntriesByPath(path, pageIndex, pageSize, out totalRecords); + return contents; + } + } + /// /// Rebuilds all xml content in the cmsContentXml table for all media /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index bc1aa0c8f6..20ae823015 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -429,6 +429,7 @@ + diff --git a/src/Umbraco.Tests.Benchmarks/BulkInsertBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/BulkInsertBenchmarks.cs index 05b14a528a..4896a6570a 100644 --- a/src/Umbraco.Tests.Benchmarks/BulkInsertBenchmarks.cs +++ b/src/Umbraco.Tests.Benchmarks/BulkInsertBenchmarks.cs @@ -1,20 +1,11 @@ using System; using System.Collections.Generic; using System.Data.SqlServerCe; -using System.Diagnostics; using System.IO; -using System.Threading; -using System.Xml; using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; -using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Diagnostics.Windows; using BenchmarkDotNet.Jobs; -using BenchmarkDotNet.Loggers; -using BenchmarkDotNet.Reports; -using BenchmarkDotNet.Running; -using BenchmarkDotNet.Validators; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models.Rdbms; diff --git a/src/Umbraco.Tests.Benchmarks/Program.cs b/src/Umbraco.Tests.Benchmarks/Program.cs index eaac2abc0d..52736ed6a4 100644 --- a/src/Umbraco.Tests.Benchmarks/Program.cs +++ b/src/Umbraco.Tests.Benchmarks/Program.cs @@ -1,20 +1,30 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Reflection; using BenchmarkDotNet.Running; namespace Umbraco.Tests.Benchmarks { - class Program + internal class Program { - static void Main(string[] args) + public static void Main(string[] args) { - var summary = BenchmarkRunner.Run(); - //var summary = BenchmarkRunner.Run(); - - Console.ReadLine(); + if (args.Length == 1) + { + var type = Assembly.GetExecutingAssembly().GetType("Umbraco.Tests.Benchmarks." +args[0]); + if (type == null) + { + Console.WriteLine("Unknown benchmark."); + } + else + { + var summary = BenchmarkRunner.Run(type); + Console.ReadLine(); + } + } + else + { + Console.WriteLine("?"); + } } } } diff --git a/src/Umbraco.Tests.Benchmarks/TraceEvent.ReleaseNotes.txt b/src/Umbraco.Tests.Benchmarks/TraceEvent.ReleaseNotes.txt deleted file mode 100644 index 21fcb5d0ca..0000000000 --- a/src/Umbraco.Tests.Benchmarks/TraceEvent.ReleaseNotes.txt +++ /dev/null @@ -1,61 +0,0 @@ -Version 1.0.0.3 - Initial release to NuGet, pre-release. - - TraceEvent has been available from the site http://bcl.codeplex.com/wikipage?title=TraceEvent for some time now - this NuGet Version of the library supersedes that one. WHile the 'core' part of the library is unchanged, - we did change lesser used features, and change the namespace and DLL name, which will cause break. We anticipate - it will take an hour or so to 'port' to this version from the old one. Below are specific details on what - has changed to help in this port. - - * The DLL has been renamed from TraceEvent.dll to Microsoft.Diagnostics.Tracing.TraceEvent.dll - * The name spaces for all classes have been changed. The easiest way to port is to simply place - the following using clauses at the top of any file that uses TraceEvent classes - using Microsoft.Diagnostics.Symbols; - using Microsoft.Diagnostics.Tracing; - using Microsoft.Diagnostics.Tracing.Etlx; - using Microsoft.Diagnostics.Tracing.Parsers.Clr; - using Microsoft.Diagnostics.Tracing.Parsers.Kernel; - using Microsoft.Diagnostics.Tracing.Session; - using Microsoft.Diagnostics.Tracing.Stacks; - * Any method with the name RelMSec in it has been changed to be RelativeMSec. The easiest port is to - simply globally rename RelMSec to RelativeMSec - * Any property in the Trace* classes that has the form Max*Index has been renamed to Count. - * A number of methods have been declared obsolete, these are mostly renames and the warning will tell you - how to update them. - * The following classes have been rename - SymPath -> SymbolPath - SymPathElement -> SymbolPathElement - SymbolReaderFlags -> SymbolReaderOptions - * TraceEventSession is now StopOnDispose (it will stop the session when TraceEventSesssion dies), by default - If you were relying on the kernel session living past the process that started it, you must now set - the StopOnDispose explicitly - * There used to be XmlAttrib extensions methods on StringBuilder for use in manifest generated TraceEventParsers - These have been moved to protected members of TraceEvent. The result is that in stead of writing - sb.XmlAttrib(...) you write XmlAttrib(sb, ...) - * References to Pdb in names have been replaced with 'Symbol' to conform to naming guidelines. - - *********************************************************************************************** -Version 1.0.0.4 - Initial stable release - - Mostly this was insuring that the library was cleaned up in preparation - for release the TraceParserGen tool - - Improved the docs, removed old code, fixed some naming convention stuff - - * Additional changes from the PreRelease copy to the first Stable release - - * The arguments to AddCallbackForProviderEvent were reversed!!!! (now provider than event) - * The arguments to Observe(string, string)!!!! (now provider than event) - * Event names for these APIs must include a / between the Task and Opcode names - - * Many Events in KernelTraceEventParser were harmonized to be consistent with other conventions - * Events of the form PageFault* were typically renamed to Memory* - * The 'End' suffix was renamed to 'Stop' (its official name) - * PerfInfoSampleProf -> PerfInfoSample - * PerfInfoSampleProf -> PerfInfoSample - * ReadyThread -> DispatcherReadyThread - * StackWalkTraceData -> StackWalkStackTraceData - * FileIo -> FileIO - * DiskIo -> DiskIO - - * Many Events in SymbolTraceEventParser were harmonized to be consistent with other conventions - * names with Symbol -> ImageID diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index f6ef93fb20..697b6a10c6 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -100,6 +100,7 @@ + diff --git a/src/Umbraco.Tests.Benchmarks/XmlBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/XmlBenchmarks.cs new file mode 100644 index 0000000000..c12545ec94 --- /dev/null +++ b/src/Umbraco.Tests.Benchmarks/XmlBenchmarks.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Diagnostics.Windows; +using BenchmarkDotNet.Jobs; + +namespace Umbraco.Tests.Benchmarks +{ + [Config(typeof(Config))] + public class XmlBenchmarks + { + private class Config : ManualConfig + { + public Config() + { + Add(new MemoryDiagnoser()); + //Add(ExecutionValidator.FailOnError); + + //The 'quick and dirty' settings, so it runs a little quicker + // see benchmarkdotnet FAQ + Add(Job.Default + .WithLaunchCount(1) // benchmark process will be launched only once + .WithIterationTime(100) // 100ms per iteration + .WithWarmupCount(3) // 3 warmup iteration + .WithTargetCount(3)); // 3 target iteration + } + } + + [Setup] + public void Setup() + { + var templateId = 0; + var xmlText = @" + + + + +]> + + + + + 1 + + This is some content]]> + + + + + + + + + + + + + + + + +"; + _xml = new XmlDocument(); + _xml.LoadXml(xmlText); + } + + [Cleanup] + public void Cleanup() + { + _xml = null; + } + + private XmlDocument _xml; + + [Benchmark] + public void XmlWithXPath() + { + var xpath = "/root/* [@isDoc and @urlName='home']//* [@isDoc and @urlName='sub1']//* [@isDoc and @urlName='sub2']"; + var elt = _xml.SelectSingleNode(xpath); + if (elt == null) Console.WriteLine("ERR"); + } + + [Benchmark] + public void XmlWithNavigation() + { + var elt = _xml.DocumentElement; + var id = NavigateElementRoute(elt, new[] {"home", "sub1", "sub2"}); + if (id <= 0) Console.WriteLine("ERR"); + } + + private const bool UseLegacySchema = false; + + private int NavigateElementRoute(XmlElement elt, string[] urlParts) + { + var found = true; + var i = 0; + while (found && i < urlParts.Length) + { + found = false; + foreach (XmlElement child in elt.ChildNodes) + { + var noNode = UseLegacySchema + ? child.Name != "node" + : child.GetAttributeNode("isDoc") == null; + if (noNode) continue; + if (child.GetAttribute("urlName") != urlParts[i]) continue; + + found = true; + elt = child; + break; + } + i++; + } + return found ? int.Parse(elt.GetAttribute("id")) : -1; + } + } +} diff --git a/src/Umbraco.Tests/PublishedContent/LegacyExamineBackedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/LegacyExamineBackedMediaTests.cs index 8a83bea75a..5bf6a4edc5 100644 --- a/src/Umbraco.Tests/PublishedContent/LegacyExamineBackedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/LegacyExamineBackedMediaTests.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Persistence.Mappers; namespace Umbraco.Tests.PublishedContent { + [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)] public class LegacyExamineBackedMediaTests : ExamineBaseTest { public override void Initialize() diff --git a/src/Umbraco.Tests/UmbracoExamine/EventsTest.cs b/src/Umbraco.Tests/UmbracoExamine/EventsTest.cs index 6bd01c7f1c..3e7377f3b6 100644 --- a/src/Umbraco.Tests/UmbracoExamine/EventsTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/EventsTest.cs @@ -3,11 +3,13 @@ using System.Linq; using Examine; using Lucene.Net.Store; using NUnit.Framework; +using Umbraco.Tests.TestHelpers; using UmbracoExamine; namespace Umbraco.Tests.UmbracoExamine { - [TestFixture] + [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)] + [TestFixture] public class EventsTest : ExamineBaseTest { [Test] diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index b303eed997..00e94ced63 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Xml.Linq; using Examine; using Examine.LuceneEngine.Config; using Examine.LuceneEngine.Providers; @@ -7,10 +9,14 @@ using Lucene.Net.Analysis; using Lucene.Net.Analysis.Standard; using Lucene.Net.Store; using Moq; +using Umbraco.Core; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Services; using UmbracoExamine; using UmbracoExamine.Config; @@ -34,7 +40,8 @@ namespace Umbraco.Tests.UmbracoExamine IMediaService mediaService = null, IDataTypeService dataTypeService = null, IMemberService memberService = null, - IUserService userService = null) + IUserService userService = null, + IContentTypeService contentTypeService = null) { if (dataService == null) { @@ -94,7 +101,8 @@ namespace Umbraco.Tests.UmbracoExamine long longTotalRecs; int intTotalRecs; - var allRecs = dataService.MediaService.GetLatestMediaByXpath("//node") + var mediaXml = dataService.MediaService.GetLatestMediaByXpath("//node"); + var allRecs = mediaXml .Root .Elements() .Select(x => Mock.Of( @@ -114,20 +122,29 @@ namespace Umbraco.Tests.UmbracoExamine mt.Id == (int)x.Attribute("nodeType")))) .ToArray(); + // MOCK! + var mediaServiceMock = new Mock(); + + mediaServiceMock + .Setup(x => x.GetPagedDescendants( + It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()) + ).Returns(() => allRecs); + + mediaServiceMock + .Setup(x => x.GetPagedDescendants( + It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny()) + ).Returns(() => allRecs); + + mediaServiceMock + .Setup(x => x.GetPagedDescendants( + It.IsAny(), It.IsAny(), It.IsAny(), out intTotalRecs, It.IsAny(), It.IsAny(), It.IsAny()) + ).Returns(() => allRecs); + + mediaServiceMock.Setup(service => service.GetPagedXmlEntries(It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs)) + .Returns(() => allRecs.Select(x => x.ToXml())); + + mediaService = mediaServiceMock.Object; - mediaService = Mock.Of( - x => x.GetPagedDescendants( - It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()) - == - allRecs - && x.GetPagedDescendants( - It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny()) - == - allRecs - && x.GetPagedDescendants( - It.IsAny(), It.IsAny(), It.IsAny(), out intTotalRecs, It.IsAny(), It.IsAny(), It.IsAny()) - == - allRecs); } if (dataTypeService == null) { @@ -139,6 +156,18 @@ namespace Umbraco.Tests.UmbracoExamine memberService = Mock.Of(); } + if (contentTypeService == null) + { + var contentTypeServiceMock = new Mock(); + contentTypeServiceMock.Setup(x => x.GetAllMediaTypes()) + .Returns(new List() + { + new MediaType(-1) {Alias = "Folder", Name = "Folder", Id = 1031, Icon = "icon-folder"}, + new MediaType(-1) {Alias = "Image", Name = "Image", Id = 1032, Icon = "icon-picture"} + }); + contentTypeService = contentTypeServiceMock.Object; + } + if (analyzer == null) { analyzer = new StandardAnalyzer(Version.LUCENE_29); @@ -154,6 +183,7 @@ namespace Umbraco.Tests.UmbracoExamine mediaService, dataTypeService, userService, + contentTypeService, analyzer, false); diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs b/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs index 7c36dd2953..5d6812f94a 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs @@ -10,15 +10,17 @@ using Lucene.Net.Index; using Lucene.Net.Search; using Lucene.Net.Store; using NUnit.Framework; +using Umbraco.Tests.TestHelpers; using UmbracoExamine; namespace Umbraco.Tests.UmbracoExamine { - /// - /// Tests the standard indexing capabilities - /// - [TestFixture, RequiresSTA] + /// + /// Tests the standard indexing capabilities + /// + [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)] + [TestFixture, RequiresSTA] public class IndexTest : ExamineBaseTest { @@ -85,12 +87,11 @@ namespace Umbraco.Tests.UmbracoExamine //RESET the parent id existingCriteria = ((IndexCriteria)_indexer.IndexerData); _indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes, - null); + null); //now ensure it's deleted var newResults = _searcher.Search(_searcher.CreateSearchCriteria().Id(2112).Compile()); Assert.AreEqual(1, newResults.Count()); - } [Test] diff --git a/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs b/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs index bcd9922e21..9b8b3d50d7 100644 --- a/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs +++ b/src/Umbraco.Tests/UmbracoExamine/SearchTests.cs @@ -8,9 +8,11 @@ using Examine.LuceneEngine.Providers; using Lucene.Net.Store; using NUnit.Framework; using Examine.LuceneEngine.SearchCriteria; +using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.UmbracoExamine { + [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)] [TestFixture] public class SearchTests : ExamineBaseTest { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js index e0678c1065..6cafa05bc8 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js @@ -10,212 +10,223 @@ /* TODO .directive("umbFileDrop", function ($timeout, $upload, localizationService, umbRequestHelper){ - - return{ - restrict: "A", - link: function(scope, element, attrs){ - - //load in the options model - - - } - } + return{ + restrict: "A", + link: function(scope, element, attrs){ + //load in the options model + } + } }) */ angular.module("umbraco.directives") + .directive('umbFileDropzone', + function($timeout, Upload, localizationService, umbRequestHelper) { + return { + restrict: 'E', + replace: true, + templateUrl: 'views/components/upload/umb-file-dropzone.html', + scope: { + parentId: '@', + contentTypeAlias: '@', + propertyAlias: '@', + accept: '@', + maxFileSize: '@', -.directive('umbFileDropzone', function ($timeout, Upload, localizationService, umbRequestHelper) { - return { + compact: '@', + hideDropzone: '@', + acceptedMediatypes: '=', - restrict: 'E', - replace: true, + filesQueued: '=', + handleFile: '=', + filesUploaded: '=' + }, + link: function(scope, element, attrs) { + scope.queue = []; + scope.done = []; + scope.rejected = []; + scope.currentFile = undefined; - templateUrl: 'views/components/upload/umb-file-dropzone.html', + function _filterFile(file) { + var ignoreFileNames = ['Thumbs.db']; + var ignoreFileTypes = ['directory']; - scope: { - parentId: '@', - contentTypeAlias: '@', - propertyAlias: '@', - accept: '@', - maxFileSize: '@', + // ignore files with names from the list + // ignore files with types from the list + // ignore files which starts with "." + if (ignoreFileNames.indexOf(file.name) === -1 && + ignoreFileTypes.indexOf(file.type) === -1 && + file.name.indexOf(".") !== 0) { + return true; + } else { + return false; + } + } - compact: '@', - hideDropzone: '@', + function _filesQueued(files, event) { + //Push into the queue + angular.forEach(files, + function(file) { - filesQueued: '=', - handleFile: '=', - filesUploaded: '=' - }, + if (_filterFile(file) === true) { - link: function(scope, element, attrs) { + if (file.$error) { + scope.rejected.push(file); + } else { + scope.queue.push(file); + } + } + }); - scope.queue = []; - scope.done = []; - scope.rejected = []; - scope.currentFile = undefined; + //when queue is done, kick the uploader + if (!scope.working) { + // Upload not allowed + if (!scope.acceptedMediatypes || !scope.acceptedMediatypes.length) { + files.map(function(file) { + file.uploadStatus = "error"; + file.serverErrorMessage = "File type is not allowed here"; + scope.rejected.push(file); + }); + scope.queue = []; + } + // One allowed type + if (scope.acceptedMediatypes && scope.acceptedMediatypes.length === 1) { + // Standard setup - set alias to auto select to let the server best decide which media type to use + if (scope.acceptedMediatypes[0].alias === 'Image') { + scope.contentTypeAlias = "umbracoAutoSelect"; + } else { + scope.contentTypeAlias = scope.acceptedMediatypes[0].alias; + } - function _filterFile(file) { + _processQueueItem(); + } + // More than one, open dialog + if (scope.acceptedMediatypes && scope.acceptedMediatypes.length > 1) { + _chooseMediaType(); + } + } + } - var ignoreFileNames = ['Thumbs.db']; - var ignoreFileTypes = ['directory']; + function _processQueueItem() { + if (scope.queue.length > 0) { + scope.currentFile = scope.queue.shift(); + _upload(scope.currentFile); + } else if (scope.done.length > 0) { + if (scope.filesUploaded) { + //queue is empty, trigger the done action + scope.filesUploaded(scope.done); + } - // ignore files with names from the list - // ignore files with types from the list - // ignore files which starts with "." - if(ignoreFileNames.indexOf(file.name) === -1 && - ignoreFileTypes.indexOf(file.type) === -1 && - file.name.indexOf(".") !== 0) { - return true; - } else { - return false; - } + //auto-clear the done queue after 3 secs + var currentLength = scope.done.length; + $timeout(function() { + scope.done.splice(0, currentLength); + }, + 3000); + } + } - } + function _upload(file) { - function _filesQueued(files, event){ + scope.propertyAlias = scope.propertyAlias ? scope.propertyAlias : "umbracoFile"; + scope.contentTypeAlias = scope.contentTypeAlias ? scope.contentTypeAlias : "Image"; - //Push into the queue - angular.forEach(files, function(file){ + Upload.upload({ + url: umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostAddFile"), + fields: { + 'currentFolder': scope.parentId, + 'contentTypeAlias': scope.contentTypeAlias, + 'propertyAlias': scope.propertyAlias, + 'path': file.path + }, + file: file + }) + .progress(function(evt) { + // calculate progress in percentage + var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10); + // set percentage property on file + file.uploadProgress = progressPercentage; + // set uploading status on file + file.uploadStatus = "uploading"; + }) + .success(function(data, status, headers, config) { + if (data.notifications && data.notifications.length > 0) { + // set error status on file + file.uploadStatus = "error"; + // Throw message back to user with the cause of the error + file.serverErrorMessage = data.notifications[0].message; + // Put the file in the rejected pool + scope.rejected.push(file); + } else { + // set done status on file + file.uploadStatus = "done"; + // set date/time for when done - used for sorting + file.doneDate = new Date(); + // Put the file in the done pool + scope.done.push(file); + } + scope.currentFile = undefined; + //after processing, test if everthing is done + _processQueueItem(); + }) + .error(function(evt, status, headers, config) { + // set status done + file.uploadStatus = "error"; + //if the service returns a detailed error + if (evt.InnerException) { + file.serverErrorMessage = evt.InnerException.ExceptionMessage; + //Check if its the common "too large file" exception + if (evt.InnerException.StackTrace && + evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) { + file.serverErrorMessage = "File too large to upload"; + } + } else if (evt.Message) { + file.serverErrorMessage = evt.Message; + } + // If file not found, server will return a 404 and display this message + if (status === 404) { + file.serverErrorMessage = "File not found"; + } + //after processing, test if everthing is done + scope.rejected.push(file); + scope.currentFile = undefined; + _processQueueItem(); + }); + } - if(_filterFile(file) === true) { + function _chooseMediaType() { + scope.mediatypepickerOverlay = { + view: "mediatypepicker", + title: "Choose media type", + acceptedMediatypes: scope.acceptedMediatypes, + hideSubmitButton: true, + show: true, + submit: function(model) { + scope.contentTypeAlias = model.selectedType.alias; + scope.mediatypepickerOverlay.show = false; + scope.mediatypepickerOverlay = null; + _processQueueItem(); + }, + close: function(oldModel) { - if(file.$error) { - scope.rejected.push(file); - } else { - scope.queue.push(file); - } + scope.queue.map(function(file) { + file.uploadStatus = "error"; + file.serverErrorMessage = "Cannot upload this file, no mediatype selected"; + scope.rejected.push(file); + }); + scope.queue = []; + scope.mediatypepickerOverlay.show = false; + scope.mediatypepickerOverlay = null; + } + }; + } - } - - }); - - //when queue is done, kick the uploader - if(!scope.working){ - _processQueueItem(); - } - } - - - function _processQueueItem(){ - - if(scope.queue.length > 0){ - scope.currentFile = scope.queue.shift(); - _upload(scope.currentFile); - }else if(scope.done.length > 0){ - - if(scope.filesUploaded){ - //queue is empty, trigger the done action - scope.filesUploaded(scope.done); - } - - //auto-clear the done queue after 3 secs - var currentLength = scope.done.length; - $timeout(function(){ - scope.done.splice(0, currentLength); - }, 3000); - } - } - - function _upload(file) { - - scope.propertyAlias = scope.propertyAlias ? scope.propertyAlias : "umbracoFile"; - scope.contentTypeAlias = scope.contentTypeAlias ? scope.contentTypeAlias : "Image"; - - Upload.upload({ - url: umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostAddFile"), - fields: { - 'currentFolder': scope.parentId, - 'contentTypeAlias': scope.contentTypeAlias, - 'propertyAlias': scope.propertyAlias, - 'path': file.path - }, - file: file - }).progress(function (evt) { - - // calculate progress in percentage - var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10); - - // set percentage property on file - file.uploadProgress = progressPercentage; - - // set uploading status on file - file.uploadStatus = "uploading"; - - }).success(function (data, status, headers, config) { - - if(data.notifications && data.notifications.length > 0) { - - // set error status on file - file.uploadStatus = "error"; - - // Throw message back to user with the cause of the error - file.serverErrorMessage = data.notifications[0].message; - - // Put the file in the rejected pool - scope.rejected.push(file); - - } else { - - // set done status on file - file.uploadStatus = "done"; - - // set date/time for when done - used for sorting - file.doneDate = new Date(); - - // Put the file in the done pool - scope.done.push(file); - - } - - scope.currentFile = undefined; - - //after processing, test if everthing is done - _processQueueItem(); - - }).error( function (evt, status, headers, config) { - - // set status done - file.uploadStatus = "error"; - - //if the service returns a detailed error - if (evt.InnerException) { - file.serverErrorMessage = evt.InnerException.ExceptionMessage; - - //Check if its the common "too large file" exception - if (evt.InnerException.StackTrace && evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) { - file.serverErrorMessage = "File too large to upload"; - } - - } else if (evt.Message) { - file.serverErrorMessage = evt.Message; - } - - // If file not found, server will return a 404 and display this message - if(status === 404 ) { - file.serverErrorMessage = "File not found"; - } - - //after processing, test if everthing is done - scope.rejected.push(file); - scope.currentFile = undefined; - - _processQueueItem(); - }); - } - - - scope.handleFiles = function(files, event){ - if(scope.filesQueued){ - scope.filesQueued(files, event); - } - - _filesQueued(files, event); - - }; - - } - - - }; - }); + scope.handleFiles = function(files, event) { + if (scope.filesQueued) { + scope.filesQueued(files, event); + } + _filesQueued(files, event); + }; + } + }; + }); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/mediatypehelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/mediatypehelper.service.js new file mode 100644 index 0000000000..20e5e3799b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/services/mediatypehelper.service.js @@ -0,0 +1,58 @@ +/** + * @ngdoc service + * @name umbraco.services.mediaTypeHelper + * @description A helper service for the media types + **/ +function mediaTypeHelper(mediaTypeResource, $q) { + + var mediaTypeHelperService = { + + getAllowedImagetypes: function (mediaId){ + + // Get All allowedTypes + return mediaTypeResource.getAllowedTypes(mediaId) + .then(function(types){ + + var allowedQ = types.map(function(type){ + return mediaTypeResource.getById(type.id); + }); + + // Get full list + return $q.all(allowedQ).then(function(fullTypes){ + + // Find all the media types with an Image Cropper property editor + var filteredTypes = mediaTypeHelperService.getTypeWithEditor(fullTypes, ['Umbraco.ImageCropper']); + + // If there is only one media type with an Image Cropper we will return this one + if(filteredTypes.length === 1) { + return filteredTypes; + // If there is more than one Image cropper, custom media types have been added, and we return all media types with and Image cropper or UploadField + } else { + return mediaTypeHelperService.getTypeWithEditor(fullTypes, ['Umbraco.ImageCropper', 'Umbraco.UploadField']); + } + + }); + }); + }, + + getTypeWithEditor: function (types, editors) { + + return types.filter(function (mediatype) { + for (var i = 0; i < mediatype.groups.length; i++) { + var group = mediatype.groups[i]; + for (var j = 0; j < group.properties.length; j++) { + var property = group.properties[j]; + if( editors.indexOf(property.editor) !== -1 ) { + return mediatype; + } + } + } + }); + + } + + }; + + return mediaTypeHelperService; +} +angular.module('umbraco.services').factory('mediaTypeHelper', mediaTypeHelper); diff --git a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less index 52c4052975..e0527aefcb 100644 --- a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less +++ b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less @@ -21,7 +21,6 @@ body { font-size: 14px; line-height: 20px; color: #343434; - background-color: #F5F5F5; -webkit-transition: all 0.2s ease-in-out; -moz-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; diff --git a/src/Umbraco.Web.UI.Client/src/less/helveticons.less b/src/Umbraco.Web.UI.Client/src/less/helveticons.less index a3c2072d86..9a317e09fb 100644 --- a/src/Umbraco.Web.UI.Client/src/less/helveticons.less +++ b/src/Umbraco.Web.UI.Client/src/less/helveticons.less @@ -1569,6 +1569,7 @@ i.small{ .icon-hd:before { content: "\e1f9"; } +.icon-globe-europe-africa:before, .icon-globe-europe---africa:before { content: "\e1fa"; } diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index 00cdd4f9b1..85ab4e6e56 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -157,7 +157,7 @@ h5.-black { } .controls-row { - padding-top: 5px; + padding-bottom: 5px; margin-left: 240px; } diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 16d48807eb..573f218fb1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -232,11 +232,11 @@ ul.color-picker li a { max-height: none !important; } -.umb-sortable-thumbnails .icon-holder { +.umb-sortable-thumbnails .umb-icon-holder { text-align: center; } -.umb-sortable-thumbnails .icon-holder .icon{ +.umb-sortable-thumbnails .umb-icon-holder .icon{ font-size: 40px; line-height: 50px; color: @gray; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.controller.js index b29388be23..f337dbce18 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.controller.js @@ -1,7 +1,7 @@ //used for the media picker dialog angular.module("umbraco") .controller("Umbraco.Dialogs.MediaPickerController", - function ($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, eventsService, treeService, $cookies, $element, $timeout) { + function($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, mediaTypeHelper, eventsService, treeService) { var dialogOptions = $scope.dialogOptions; @@ -11,29 +11,34 @@ angular.module("umbraco") $scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1; $scope.cropSize = dialogOptions.cropSize; - //preload selected item $scope.target = undefined; - if(dialogOptions.currentTarget){ + if (dialogOptions.currentTarget) { $scope.target = dialogOptions.currentTarget; } - $scope.upload = function(v){ - angular.element(".umb-file-dropzone-directive .file-select").click(); + $scope.acceptedMediatypes = []; + mediaTypeHelper.getAllowedImagetypes($scope.startNodeId) + .then(function(types) { + $scope.acceptedMediatypes = types; + }); + + $scope.upload = function(v) { + angular.element(".umb-file-dropzone-directive .file-select").click(); }; - $scope.dragLeave = function(el, event){ + $scope.dragLeave = function(el, event) { $scope.activeDrag = false; }; - $scope.dragEnter = function(el, event){ + $scope.dragEnter = function(el, event) { $scope.activeDrag = true; }; $scope.submitFolder = function(e) { if (e.keyCode === 13) { e.preventDefault(); - + mediaResource .addFolder($scope.newFolderName, $scope.currentFolder.id) .then(function(data) { @@ -52,21 +57,25 @@ angular.module("umbraco") }; $scope.gotoFolder = function(folder) { - - if(!folder){ - folder = {id: -1, name: "Media", icon: "icon-folder"}; + if (!folder) { + folder = { id: -1, name: "Media", icon: "icon-folder" }; } if (folder.id > 0) { entityResource.getAncestors(folder.id, "media") .then(function(anc) { // anc.splice(0,1); - $scope.path = _.filter(anc, function (f) { - return f.path.indexOf($scope.startNodeId) !== -1; - }); + $scope.path = _.filter(anc, + function(f) { + return f.path.indexOf($scope.startNodeId) !== -1; + }); }); - } - else { + + mediaTypeHelper.getAllowedImagetypes(folder.id) + .then(function(types) { + $scope.acceptedMediatypes = types; + }); + } else { $scope.path = []; } @@ -77,49 +86,49 @@ angular.module("umbraco") $scope.images = data.items ? data.items : []; }); - $scope.currentFolder = folder; + $scope.currentFolder = folder; }; - - + + $scope.clickHandler = function(image, ev, select) { ev.preventDefault(); - + if (image.isFolder && !select) { $scope.gotoFolder(image); - }else{ + } else { eventsService.emit("dialogs.mediaPicker.select", image); - + //we have 3 options add to collection (if multi) show details, or submit it right back to the callback if ($scope.multiPicker) { $scope.select(image); image.cssclass = ($scope.dialogData.selection.indexOf(image) > -1) ? "selected" : ""; - }else if($scope.showDetails) { - $scope.target= image; + } else if ($scope.showDetails) { + $scope.target = image; $scope.target.url = mediaHelper.resolveFile(image); - }else{ + } else { $scope.submit(image); } } }; - $scope.exitDetails = function(){ - if(!$scope.currentFolder){ + $scope.exitDetails = function() { + if (!$scope.currentFolder) { $scope.gotoFolder(); } $scope.target = undefined; }; - $scope.onUploadComplete = function () { + $scope.onUploadComplete = function() { $scope.gotoFolder($scope.currentFolder); }; - $scope.onFilesQueue = function(){ + $scope.onFilesQueue = function() { $scope.activeDrag = false; }; //default root item - if(!$scope.target){ - $scope.gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" }); + if (!$scope.target) { + $scope.gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" }); } }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.html index 540a19d64a..78d8e41127 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/mediapicker.html @@ -116,8 +116,10 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js index e74bfd20a4..8e87a2daff 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js @@ -326,7 +326,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController", } }); } else { - var a = dialogOptions.filter.toLowerCase().split(','); + var a = dialogOptions.filter.toLowerCase().replace(/\s/g, '').split(','); angular.forEach(nodes, function (value, key) { var found = a.indexOf(value.metaData.contentType.toLowerCase()) >= 0; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html b/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html index 6a05d234f0..6b05593e11 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html @@ -98,4 +98,11 @@ + + + diff --git a/src/Umbraco.Web.UI.Client/src/views/content/copy.html b/src/Umbraco.Web.UI.Client/src/views/content/copy.html index 3f2bfcdd3b..371e156513 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/copy.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/copy.html @@ -51,13 +51,14 @@ - - + + + - + diff --git a/src/Umbraco.Web.UI.Client/src/views/content/move.html b/src/Umbraco.Web.UI.Client/src/views/content/move.html index b64511ec22..6bf3ca817a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/move.html @@ -3,9 +3,11 @@

- Choose where to move {{currentNode.name}} to in the tree structure below + Choose where to move + {{currentNode.name}} + to in the tree structure below

- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardIntro.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardIntro.html index 73a6399b67..3782898312 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardIntro.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/default/StartupDashboardIntro.html @@ -1,44 +1,44 @@ -
- - - -
- -
-
- - -
-
- - -
-
- - -
-
-
-
-
- -
-
- -
-
-
- - -
-
- - - - -
-

Welcome to The Friendly CMS

+
+ + + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ +
+
+ +
+
+
+ + +
+
+ + + + +
+

Welcome to The Friendly CMS

Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible.

@@ -50,46 +50,46 @@
  • Watch our tutorial videos (some are free, some require a subscription)
  • Find out about our productivity boosting tools and commercial support
  • Find out about real-life training and certification opportunities
  • - - -
    -
    - - Umbraco.TV - Hours of Umbraco Video Tutorials - - - - -

    Umbraco.TV - Learn from the source!

    -
    - -

    - Umbraco.TV will help you go from zero to Umbraco - hero at a pace that suits you. Our easy to follow - online training videos will give you the fundamental - knowledge to start building awesome Umbraco websites. -

    -
    - -
    - - - Our Umbraco - - - -

    Our Umbraco - The Friendliest Community

    -
    - -

    - Our Umbraco - the official community site is your one - stop for everything Umbraco. Whether you need a - question answered or looking for cool plugins, the - worlds best community is just a click away. -

    - -
    -
    -
    - + + +
    +
    + + Umbraco.TV - Hours of Umbraco Video Tutorials + + + + +

    Umbraco.TV - Learn from the source!

    +
    + +

    + Umbraco.TV will help you go from zero to Umbraco + hero at a pace that suits you. Our easy to follow + online training videos will give you the fundamental + knowledge to start building awesome Umbraco websites. +

    +
    + +
    + + + Our Umbraco + + + +

    Our Umbraco - The Friendliest Community

    +
    + +

    + Our Umbraco - the official community site is your one + stop for everything Umbraco. Whether you need a + question answered or looking for cool plugins, the + worlds best community is just a click away. +

    + +
    +
    +
    +
    \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/media/move.html b/src/Umbraco.Web.UI.Client/src/views/media/move.html index 95c30dfc40..3f71340ee3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/move.html +++ b/src/Umbraco.Web.UI.Client/src/views/media/move.html @@ -3,8 +3,10 @@

    - Choose where to move {{currentNode.name}} to in the tree structure below -

    + Choose where to move + {{currentNode.name}} + to in the tree structure below +

    {{error.errorMsg}}

    diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/grid/grid.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/grid/grid.html index 4360996b55..16c5efe799 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/grid/grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/grid/grid.html @@ -39,7 +39,8 @@ on-drag-enter="vm.dragEnter()"> - + {{image.name}} diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 6f2728a241..a31d174e14 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2412,9 +2412,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" True True - 7540 + 7550 / - http://localhost:7540 + http://localhost:7550 False False diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index ffb0a9d96b..b0452fb631 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -30,6 +30,9 @@ Genindlæs elementer Genudgiv hele sitet Gendan + Sæt rettigheder for siden %0% + Hvor vil du flytte + hen til i træstrukturen? Rettigheder Fortryd ændringer Send til udgivelse @@ -202,12 +205,12 @@ Færdig - + Slettede %0% element Slettede %0% elementer Slettede %0% ud af %1% element Slettede %0% ud af %1% elementer - + Udgav %0% element Udgav %0% elementer Udgav %0% ud af %1% element @@ -274,17 +277,11 @@ Vælg Se cache element Opret mappe... - Relatér til original - + Inkludér undersider Link til side - - Åbner det linket dokument i et nyt vindue eller fane - Åbner det linket dokument i fuld visning af vinduet - Åbner det linket dokument i "parent frame" - + Åben linket i et nyt vindue eller fane Link til medie - Vælg medie Vælg ikon Vælg item @@ -293,20 +290,18 @@ Vælg indhold Vælg medlem Vælg medlemsgruppe - Der er ingen parametre for denne makro - Link dit - Fjern link fra dit - + Fjern link fra dit konto - Vælg editor - + Du tilføjer flere sprog under 'sprog' i menuen til venstre - ]]> + ]]> + Kulturnavn Rediger navnet på ordbogselementet. @@ -327,17 +322,17 @@ Indtast nøgleord (tryk på Enter efter hvert nøgleord)... - Tillad på rodniveau + Tillad på rodniveau Kun dokumenttyper med denne indstilling aktiveret oprettes i rodniveau under Inhold og Mediearkiv Tilladte typer - Sammensætning af dokumenttyper + Sammensætning af dokumenttyper Opret Slet fane Beskrivelse Ny fane Fane Thumbnail - Aktiver listevisning + Aktiver listevisning Viser undersider i en søgbar liste, undersider vises ikke i indholdstræet Nuværende listevisning Den aktive listevisningsdatatype @@ -372,7 +367,7 @@ Der skete en fejl på severen - Denne filttype er blevet deaktiveret af administratoren + Denne filttype er blevet deaktiveret af administratoren OBS! Selvom CodeMirror er slået til i konfigurationen, så er den deaktiveret i Internet Explorer fordi den ikke er stabil nok. Du skal udfylde både Alias & Navn på den nye egenskabstype! Der mangler læse/skrive rettigheder til bestemte filer og mapper @@ -388,7 +383,7 @@ Du kan ikke opdele en celle, som ikke allerede er delt. Fejl i XSLT kode Din XSLT er ikke opdateret, da det indeholdt en fejl - Der er et problem med den datatype, der bruges til denn egenskab. Kontroller konfigurationen og prøv igen. + Der er et problem med den datatype, der bruges til denn egenskab. Kontroller konfigurationen og prøv igen. Om @@ -474,7 +469,8 @@ Hvilken side skal vises efter at formularen er sendt Størrelse Sortér - Indsend + Indsend + Type Skriv for at søge... Op @@ -513,22 +509,22 @@ - Tilføj fane - Tilføj egenskab - Tilføj editor - Tilføj skabelon - Tilføj child node - Tilføj child + Tilføj fane + Tilføj egenskab + Tilføj editor + Tilføj skabelon + Tilføj child node + Tilføj child - Rediger datatype + Rediger datatype - Naviger sektioner + Naviger sektioner - Genveje - Vis genveje + Genveje + Vis genveje - Brug listevisning - Tillad på rodniveau + Brug listevisning + Tillad på rodniveau @@ -546,13 +542,17 @@ Kunne ikke gemme web.config filen. Du bedes venligst manuelt ændre database forbindelses strengen. Din database er blevet fundet og identificeret som Database konfiguration - + installér knappen for at installere Umbraco %0% databasen - ]]> + ]]> + installér knappen for at installere Umbraco %0% databasen]]> Næste for at fortsætte.]]> - Databasen er ikke fundet. Kontrollér venligst at informationen i database forbindelsesstrengen i "web.config" filen er korrekt.

    -

    For at fortsætte bedes du venligst rette "web.config" filen (ved at bruge Visual Studio eller dit favoritprogram), scroll til bunden, tilføj forbindelsesstrengen til din database i feltet som hedder "umbracoDbDSN" og gem filen.

    Klik på Forsøg igen knappen når du er færdig.
    Mere information om at redigere web.config her.

    ]]>
    + + Databasen er ikke fundet. Kontrollér venligst at informationen i database forbindelsesstrengen i "web.config" filen er korrekt.

    +

    For at fortsætte bedes du venligst rette "web.config" filen (ved at bruge Visual Studio eller dit favoritprogram), scroll til bunden, tilføj forbindelsesstrengen til din database i feltet som hedder "umbracoDbDSN" og gem filen.

    Klik på Forsøg igen knappen når du er færdig.
    Mere information om at redigere web.config her.

    ]]> +
    Kontakt venligst din ISP hvis det er nødvendigt. Hvis du installerer på en lokal maskine eller server kan du muligvis få informationerne fra din systemadministrator.]]> Tryk på Opgradér knappen for at opgradere din database til Umbraco %0%

    Bare rolig - intet indhold vil blive slettet og alt vil stadig fungere bagefter!

    ]]>
    Tryk på Næste for at fortsætte.]]> @@ -598,8 +598,10 @@ Yderligere hjælpe og informationer Få hjælp fra vores prisvindende fællesskab, gennemse dokumentationen eller se nogle gratis videoer om hvordan du opsætter et simpelt site, hvordan du bruger pakker og en 'quick guide' til Umbraco terminologier]]> Umbraco %0% er installeret og klar til brug /web.config filen og opdatére 'AppSetting' feltet UmbracoConfigurationStatus i bunden til '%0%'.]]> - komme igang med det samme ved at klikke på "Start Umbraco" knappen nedenfor.
    Hvis du er ny med Umbraco, kan du finde masser af ressourcer på vores 'getting started' sider. -]]>
    + + komme igang med det samme ved at klikke på "Start Umbraco" knappen nedenfor.
    Hvis du er ny med Umbraco, kan du finde masser af ressourcer på vores 'getting started' sider. +]]> +
    Start UmbracoFor at administrere dit website skal du blot åbne Umbraco administrationen og begynde at tilføje indhold, opdatere skabelonerne og stylesheets'ene eller tilføje ny funktionalitet.]]> Forbindelse til databasen fejlede. Umbraco Version 3 @@ -674,12 +676,15 @@ Gå til http://%4%/#/content/content/edit/%5% for at redigere. Ha' en dejlig dag! Mange hilsner fra Umbraco robotten - ]]> - Hej %0%

    + ]]> +
    + + Hej %0%

    Dette er en automatisk mail for at informere dig om at opgaven '%1%' er blevet udførtpå siden '%2%' af brugeren '%3%'

    Opdateringssammendrag:

    %6%

    Hav en fortsat god dag!

    De bedste hilsner fra umbraco robotten

    ]]>
    +      RET       

    Opdateringssammendrag:

    %6%

    Hav en fortsat god dag!

    De bedste hilsner fra umbraco robotten

    ]]> + [%0%] Notificering om %1% udført på %2% Notificeringer @@ -700,8 +705,10 @@ Mange hilsner fra Umbraco robotten Pakken blev fjernet Pakken er på succefuld vis blevet fjernet Afinstallér pakke - -Bemærk: at dokumenter og medier som afhænger af denne pakke vil muligvis holde op med at virke, så vær forsigtig. Hvis i tvivl, kontakt personen som har udviklet pakken.]]> + + +Bemærk: at dokumenter og medier som afhænger af denne pakke vil muligvis holde op med at virke, så vær forsigtig. Hvis i tvivl, kontakt personen som har udviklet pakken.]]> + Download opdatering fra opbevaringsbasen Opdatér pakke Opdateringsinstrukser @@ -734,6 +741,19 @@ Mange hilsner fra Umbraco robotten Hvis du blot ønsker at opsætte simpel beskyttelse ved hjælp af et enkelt login og kodeord + Udgivelsen kunne ikke udgives da publiceringsdato er sat + + + + + + + Udgivelsen fejlede fordi en overordnet side ikke er publiceret + %0% kunne ikke udgives, fordi et 3. parts modul annullerede handlingen Medtag ikke-udgivede undersider Publicerer - vent venligst... @@ -807,58 +827,58 @@ Mange hilsner fra Umbraco robotten - Kompositioner - Du har ikke tilføjet nogle faner - Tilføj ny fane - Tilføj endnu en fane - Nedarvet fra - Tilføj property - Påkrævet label + Kompositioner + Du har ikke tilføjet nogle faner + Tilføj ny fane + Tilføj endnu en fane + Nedarvet fra + Tilføj property + Påkrævet label - Aktiver listevisning - Konfigurer indholdet til at blive vist i en sorterbar og søgbar liste, dens børn vil ikke blive vist i træet + Aktiver listevisning + Konfigurer indholdet til at blive vist i en sorterbar og søgbar liste, dens børn vil ikke blive vist i træet - Tilladte skabeloner - Vælg hvilke skabeloner der er tilladt at bruge på dette indhold + Tilladte skabeloner + Vælg hvilke skabeloner der er tilladt at bruge på dette indhold - Tillad på rodniveau - Kun dokumenttyper med denne indstilling aktiveret oprettes i rodniveau under inhold og mediearkiv - Ja – indhold af denne type er tilladt i roden + Tillad på rodniveau + Kun dokumenttyper med denne indstilling aktiveret oprettes i rodniveau under inhold og mediearkiv + Ja – indhold af denne type er tilladt i roden - Tilladte typer - Tillad at oprette indhold af en specifik type under denne + Tilladte typer + Tillad at oprette indhold af en specifik type under denne - Vælg child node + Vælg child node - Nedarv faner og egenskaber fra en anden dokumenttype. Nye faner vil blive tilføjet den nuværende dokumenttype eller sammenflettet hvis fanenavnene er ens. - Indholdstypen bliver brugt i en komposition og kan derfor ikke blive anvendt som komposition - Der er ingen indholdstyper tilgængelige at bruge som komposition + Nedarv faner og egenskaber fra en anden dokumenttype. Nye faner vil blive tilføjet den nuværende dokumenttype eller sammenflettet hvis fanenavnene er ens. + Indholdstypen bliver brugt i en komposition og kan derfor ikke blive anvendt som komposition + Der er ingen indholdstyper tilgængelige at bruge som komposition - Tilgængelige editors - Genbrug - Editor indstillinger + Tilgængelige editors + Genbrug + Editor indstillinger - Konfiguration + Konfiguration - Ja, slet + Ja, slet - blev flyttet til - Vælg hvor - skal flyttes til + blev flyttet til + Vælg hvor + skal flyttes til - Alle dokumenttyper - Alle dokumenter - Alle medier + Alle dokumenttyper + Alle dokumenter + Alle medier - som benytter denne dokumenttype vil blive slettet permanent. Bekræft at du også vil slette dem. - som benytter denne medietype vil blive slettet permanent. Bekræft at du også vil slette dem. - som benytter denne medlemstype vil blive slettet permanent. Bekræft at du også vil slette dem. + som benytter denne dokumenttype vil blive slettet permanent. Bekræft at du også vil slette dem. + som benytter denne medietype vil blive slettet permanent. Bekræft at du også vil slette dem. + som benytter denne medlemstype vil blive slettet permanent. Bekræft at du også vil slette dem. - og alle dokumenter, som benytter denne type - og alle medier, som benytter denne type - og alle medlemmer, som benytter denne type + og alle dokumenter, som benytter denne type + og alle medier, som benytter denne type + og alle medlemmer, som benytter denne type - der bruger denne editor vil blive opdateret med de nye indstillinger + der bruger denne editor vil blive opdateret med de nye indstillinger @@ -922,8 +942,6 @@ Mange hilsner fra Umbraco robotten Annulleret Handlingen blev annulleret af et 3. part tilføjelsesprogram - Udgivelsen blev standset af et 3. parts modul - Udgivelsen kunne ikke udgives da publiceringsdato er sat Property type eksisterer allerede Egenskabstype oprettet DataType: %1%]]> @@ -937,7 +955,6 @@ Mange hilsner fra Umbraco robotten Stylesheet gemt uden fejl Datatype gemt Ordbogsnøgle gemt - Udgivelsen fejlede fordi en overordnet side ikke er publiceret Indhold publiceret og nu synligt for besøgende Indhold gemt @@ -1139,11 +1156,28 @@ Mange hilsner fra Umbraco robotten Session udløber - Validation - Valider som email - Valider som tal - Valider som Url - ...eller indtast din egen validering - Feltet er påkrævet + Validation + Valider som email + Valider som tal + Valider som Url + ...eller indtast din egen validering + Feltet er påkrævet + + + Slå URL tracker fra + Slå URL tracker til + Original URL + Viderestillet til + Der er ikke lavet nogen viderestillinger + Når en udgivet side bliver omdøbt eller flyttet, vil en viderestilling automatisk blive lavet til den nye side. + Fjern + Er du sikker på at du vil fjerne viderestillingen fra '%0%' til '%1%'? + Viderestillings URL fjernet. + Fejl under fjernelse af viderestillings URL. + Er du sikker på at du vil slå URL trackeren fra? + URL tracker er nu slået fra. + Der opstod en fejl under forsøget på at slå URL trackeren fra, der findes mere information i logfilen. + URL tracker er nu slået fra. + Der opstod en fejl under forsøget på at slå URL trackeren til, der findes mere information i logfilen. diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index f710e54215..bdc2647563 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -28,6 +28,9 @@ Reload Republish entire site Restore + Set permissions for the page %0% + Choose where to move + to in the tree structure below Permissions Rollback Send To Publish @@ -144,7 +147,7 @@ Role Member Type No date chosen - Page Title + Link title Properties This document is published but is not visible because the parent '%0%' is unpublished This document is published but is not in the cache @@ -286,18 +289,12 @@ Pick item View Cache Item Create folder... - Relate to original + Include descendants The friendliest community - Link to page - Opens the linked document in a new window or tab - Opens the linked document in the full body of the window - Opens the linked document in the parent frame - Link to media - Select media Select icon Select item @@ -307,19 +304,14 @@ Select member Select member group No icons were found - There are no parameters for this macro - External login providers Exception Details Stacktrace Inner Exception - Link your Un-Link your - account - Select editor @@ -1341,7 +1333,7 @@ To manage your website, simply open the Umbraco back office and start adding con Custom errors successfully set to '%0%'. MacroErrors are set to '%0%'. - MacroErrors are set to '%0%' which will prevent some or all pages in your site from loading completely when there's any errors in macros. Rectifying this will set the value to '%1%'. + MacroErrors are set to '%0%' which will prevent some or all pages in your site from loading completely if there are any errors in macros. Rectifying this will set the value to '%1%'. MacroErrors are now set to '%0%'. + Envoyer Type Rechercher... Haut @@ -431,11 +507,45 @@ Oui Dossier Résultats de recherche - Reorder - I am done reordering + Réorganiser + J'ai fini de réorganiser + Prévisualiser + Modifier le mot de passe + vers + Liste + Sauvegarde... + actuel + Intégrer + sélectionné + + + Noir + Vert + Jaune + Orange + Bleu + Rouge + + + Ajouter un onglet + Ajouter une propriété + Ajouter un éditeur + Ajouter un modèle + Ajouter un noeud enfant + Ajouter un enfant + + Editer le type de données + + Parcourir les sections + + Raccourcis + afficher les raccourcis + + Passer à la vue en liste + Basculer vers l'autorisation comme racine - Background color + Couleur de fond Gras Couleur de texte Police @@ -445,131 +555,128 @@ Page - L'installeur n'a pas pu se connecter à la base de données. - Impossible de modifier le fichier web.config file. Modifiez s'il vous plait la "connection string" manuellement. - Votre base de données a été détectée et identifiée telle que - Configurtion de la base de données + Le programme d'installation ne parvient pas à se connecter à la base de données. + Impossible de sauvegarder le fichier web.config. Veuillez modifier la "connection string" manuellement. + Votre base de données a été détectée et est identifiée comme étant + Configuration de la base de données install pour installer la base de données Umbraco %0% + Appuyez sur le bouton installer pour installer la base de données Umbraco %0% ]]> - Suivant pour procéder.]]> - Base de données non trouvée ! Vérifiez les informations de la "connection string" dans le fichier web.config.

    -

    Pour poursuivre, éditez le fichier "web.config" (avec Visual Studio ou votre éditeur de texte favori), scrollez jusqu'en bas, ajoutez une "connection string" dans la ligne "umbracoDbDSN" et sauvegardez votre fichier.

    + Suivant pour poursuivre.]]> + Base de données non trouvée ! Veuillez vérifier les informations de la "connection string" dans le fichier web.config.

    +

    Pour poursuivre, veuillez éditer le fichier "web.config" (avec Visual Studio ou votre éditeur de texte favori), scroller jusqu'en bas, ajouter le "connection string" pour votre base de données dans la ligne avec la clé "umbracoDbDSN" et sauvegarder le fichier.

    Cliquez sur le bouton Réessayer lorsque cela est fait.
    Plus d'informations sur l'édition du fichier web.config ici.

    ]]>
    - - Contactez votre administrateur système si nécessaire. - Si vous installez Umbraco sur votre ordinateur, vous aurez probablement besoin de consulter votre administrateur système.]]> + + Veuillez contacter votre fournisseur de services internet si nécessaire. + Si vous installez Umbraco sur un ordinateur ou un serveur local, vous aurez peut-être besoin de consulter votre administrateur système.]]> Appuyez sur le bouton Upgrader pour mettre à jour votre base de données vers Umbraco %0%

    - Ne vous inquiétez pas : aucun contenu ne sera supprimé et tout continuera à fonctionner parfaitement ensuite ! + N'ayez pas d'inquiétude : aucun contenu ne sera supprimé et tout continuera à fonctionner parfaitement par après !

    ]]>
    - Appuyez sur Suivant pour - poursuivre. ]]> + + Appuyez sur Suivant pour + poursuivre. ]]> + Suivant pour poursuivre la configuration]]> - Le mot de passe par défaut doit être changé !]]> - L'utilisateur par défaut a été désactivé ou n'a pas accès à Umbraco!

    Aucune action n'est requise. Cliquez sur Suivant pour poursuivre.]]> - Le mot de passe par défaut a été modifié avec succès !

    Aucune action n'est requise. Cliquez sur Suivant pour poursuivre.]]> - Le mot de passe a été changé ! - - Umbraco créer un utilisateur par défaut avec le login ('admin') et le mot de passe ('default'). - Il est important que ce mot de passe soit changé pour quelque-chose de sécurisé et unique. -

    -

    - Cette étape va vérifier le mot de passe par défaut et vérifier s'il est nécessaire de le changer. -

    - ]]>
    + Le mot de passe par défaut doit être modifié !]]> + L'utilisateur par défaut a été désactivé ou n'a pas accès à Umbraco!

    Aucune autre action n'est requise. Cliquez sur Suivant pour poursuivre.]]> + Le mot de passe par défaut a été modifié avec succès depuis l'installation!

    Aucune autre action n'est requise. Cliquez sur Suivant pour poursuivre.]]> + Le mot de passe a été modifié ! + + ('admin') et le mot de passe ('default'). Il est important que ce mot de passe soit modifié en quelque-chose de sécurisé et unique. + ]]> Pour bien commencer, regardez nos vidéos d'introduction - En cliquant sur le bouton Suvant (ou en modifiant umbracoConfigurationStatus dans le fichier web.config), vous acceptez la licence de ce logiciel telle que spécifiée dans le champ ci-dessous. Remarque : cette distribution Umbraco consiste en deux licences différentes, la licence open source MIT pour le framework et la licence Umbraco freewarequi couvre l'UI. + En cliquant sur le bouton "Suivant" (ou en modifiant umbracoConfigurationStatus dans le fichier web.config), vous acceptez la licence de ce logiciel telle que spécifiée dans le champ ci-dessous. Veuillez noter que cette distribution Umbraco consiste en deux licences différentes, la licence open source MIT pour le framework et la licence Umbraco freeware qui couvre l'UI. Pas encore installé. - Fichiers et dossiers affectés - Plus d'informations sur la définition des permissions + Fichiers et dossiers concernés + Plus d'informations sur la configuration des permissions Vous devez donner à ASP.NET les droits de modification sur les fichiers/dossiers suivants - Vos permissions sont presques parfaites !

    - Vous pouvez faire fonctionner Umbraco sans problèmes, mais vous ne serez pas en mesure d'installer des packages, ce qui est hautement recommandé pour tirer pleinement parti d'Umbraco.]]>
    - Comment le résoudre + Vos configurations de permissions sont presque parfaites !

    + Vous pouvez faire fonctionner Umbraco sans problèmes, mais vous ne serez pas en mesure d'installer des packages, ce qui est hautement recommandé pour tirer pleinement profit d'Umbraco.]]>
    + Comment résoudre Cliquez ici pour lire la version texte - tutoriel vidéo sur la définition des permissions pour Umbraco, ou lisez la version texte.]]> - Vos permissions pourraient être problématiques ! + tutoriel vidéo sur la définition des permissions des répertoires pour Umbraco, ou lisez la version texte.]]> + Vos configurations de permissions pourraient poser problème !

    - Vous pouvez faire fonctionner Umbraco sans problèmes, mais vous ne serez pas en mesure d'installer des packages, ce qui est hautement recommandé pour tirer pleinement parti d'Umbraco.]]>
    - Vos permissions ne sont pas prêtes pour Umbraco ! + Vous pouvez faire fonctionner Umbraco sans problèmes, mais vous ne serez pas en mesure d'installer des packages, ce qui est hautement recommandé pour tirer pleinement profit d'Umbraco.]]> + Vos configurations de permissions ne sont pas prêtes pour Umbraco !

    Pour faire fonctionner Umbraco, vous aurez besoin de mettre à jour les permissions sur les fichiers/dossiers.]]>
    - Vos permissions sont parfaites !

    - Vous êtes prêt à faire fonctionner Umbraco et installer des packages !]]>
    + Vos configurations de permissions sont parfaites !

    + Vous êtes prêt(e) à faire fonctionner Umbraco et à installer des packages !]]>
    Résoudre un problème sur un dossier - Suivz ce lien pour plus d'informations sur ASP.NET et la création de dossiers + Suivez ce lien pour plus d'informations sur les problèmes avec ASP.NET et la création de dossiers Définir les permissions de dossier Je veux démarrer "from scratch" - + Apprenez comment) - Vous pouvez toujours choisir d'installer Runway plus tard. Pour cela allez dans la séction "Développeur" et séléctionnez "Packages". + Vous pouvez toujours choisir d'installer Runway plus tard. Pour cela, allez dans la section "Développeur" et sélectionnez "Packages". ]]> - Vous avez mis en oeuvre une plateforme Umbraco clean. Que voulez-vous faire ensuite ? + Vous venez de mettre en place une plateforme Umbraco toute nette. Que voulez-vous faire ensuite ? Runway est installé + Les fondations en place. Choisissez les modules que vous souhaitez installer par-dessus
    Voici la liste des modules recommandés, cochez ceux que vous souhaitez installer, ou regardez la liste complète des modules ]]>
    Recommandé uniquement pour les utilisateurs expérimentés Je veux commencer avec un site simple - + - "Runway" est un simple site fournissant des types de documents et modèles basiques. L'installeur peut mettre en oeuvre Runway automatiquement pour vous, - mais vous pouvez facilement léditer, lenrichir, ou le supprimer ensuite. Il n'est pas nécessaire et vous pouvez parfaitement utiliser Umbraco sans. Pour autant, - Runway offre un socle facile basé sur des bonnes pratiques pour vous permettre de commencer rapidement. - Si vous choisissez d'installer Runway, vous pouvez, de manière optionnelle, choisir des blocks appelés Runway Modules pour enrichir les pages du site. + "Runway" est un site simple qui fournit des types de documents et des modèles de base. L'installateur peut mettre en place Runway automatiquement pour vous, + mais vous pouvez facilement l'éditer, l'enrichir, ou le supprimer par la suite. Il n'est pas nécessaire, et vous pouvez parfaitement vous en passer pour utiliser Umbraco. Cela étant dit, + Runway offre une base facile, fondée sur des bonnes pratiques, pour vous permettre de commencer plus rapidement que jamais. + Si vous choisissez d'installer Runway, vous pouvez sélectionner en option des blocs de base, appelés Runway Modules, pour enrichir les pages de votre site.

    Inclus avec Runway : Home page, Getting Started page, Installing Modules page.
    Modules optionnels : Top Navigation, Sitemap, Contact, Gallery.
    ]]>
    - Qu'est ce que Runway - Step 1/5 : Licence - Step 2/5 : Configuration base de données - Step 3/5 : Validation des permissions de fichiers - Step 4/5 : Sécurité Umbraco - Step 5/5 : Umbraco est prêt + Qu'est-ce que Runway + Etape 1/5 : Accepter la licence + Etape 2/5 : Configuration de la base de données + Etape 3/5 : Validation des permissions de fichiers + Etape 4/5 : Sécurité Umbraco + Etape 5/5 : Umbraco est prêt Merci d'avoir choisi Umbraco Parcourir votre nouveau site -Vous avez installé Runway, alors pourquoi pas jeter un oeil au look de votre nouveau site ?]]> - Aide et information -Obtenez de l'aide de notre award winning communauté, parcourez la documentation our regardez quelques vidéos sur "Comemnt construire un site simple", "Comment utiliser les packages" et un guide rapide sur la terminologie Umbraco]]> +Vous avez installé Runway, alors pourquoi ne pas jeter un oeil au look de votre nouveau site ?]]>
    + Aide et informations complémentaires +Obtenez de l'aide de notre "award winning" communauté, parcourez la documentation ou regardez quelques vidéos gratuites sur la manière de construire un site simple, d'utiliser les packages ainsi qu'un guide rapide sur la terminologie Umbraco]]> Umbraco %0% est installé et prêt à être utilisé - /web.config file et mettre à jour le paramètre AppSetting dans umbracoConfigurationStatus en bas de la valeur de '%0%'.]]> - démarrer maintenant en cliquant sur le bouton "Lancer Umbraco" ci-dessous.
    -Si vous débutez sur Umbraco, vous pouvez trouver plein de ressources sur nos pages "Getting Started".]]>
    + fichier /web.config et mettre à jour le paramètre AppSetting umbracoConfigurationStatus situé en bas à la valeur '%0%'.]]> + démarrer instantanément en cliquant sur le bouton "Lancer Umbraco" ci-dessous.
    +Si vous débutez avec Umbraco, vous pouvez trouver une foule de ressources dans nos pages "Getting Started".]]>
    Lancer Umbraco -Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à ajouter du contenu, mettez à jour les templates et feuilles de styles ou ajoutez ds nouvelles fonctionnalités]]> +Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à ajouter du contenu, à mettre à jour les modèles d'affichage et feuilles de styles ou à ajouter de nouvelles fonctionnalités]]> La connexion à la base de données a échoué. Umbraco Version 3 Umbraco Version 4 Regarder - umbraco %0%, qu'il s'agisse d'une installation récente ou de la version 3.0 + Umbraco %0%, qu'il s'agisse d'une nouvelle installation ou d'une mise à jour à partir de la version 3.0

    - Appuyez sur Press "suivant" pour commencer.]]>
    + Appuyez sur "suivant" pour commencer l'assistant.]]>
    Code de la Culture Nom de la culture - Vous avez été inactif, la déconnexion automatique se fera dans + Vous avez été inactif et la déconnexion aura lieu automatiquement dans Renouvellez votre session maintenant pour sauvegarder votre travail @@ -581,8 +688,20 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Joyeux vendredi Joyeux samedi Connectez-vous ci-dessous - La session a expiré - © 2001 - %0%
    umbraco.com

    ]]>
    + Identifiez-vous avec + La session a expiré + © 2001 - %0%
    Umbraco.com

    ]]>
    + Mot de passe oublié? + Un email contenant un lien pour ré-initialiser votre mot de passe sera envoyé à l'adresse spécifiée + Un email contenant les instructions de ré-initialisation de votre mot de passe sera envoyée à l'adresse spécifiée si elle correspond à nos informations. + Revenir au formulaire de connexion + Veuillez fournir un nouveau mot de passe + Votre mot de passe a été mis à jour + Le lien sur lequel vous avez cliqué est non valide ou a expiré. + Umbraco: Ré-initialiser le mot de passe + + Votre nom d'utilisateur pour vous connecter au back-office Umbraco est : %0%.

    Cliquez ici pour ré-initialiser votre mot de passe, ou recopiez cet URL dans votre navigateur :

    %1%

    ]]> +
    Tableau de bord @@ -590,21 +709,21 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Contenu - Choisissez une page ci-dessous... + Choisissez la page au-dessus... %0% a été copié dans %1% - Choisissez, ci-dessous, où le document %0% doit être copié + Choisissez ci-dessous l'endroit où le document %0% doit être copié %0% a été déplacé dans %1% - Choisissez, ci-dessous, où le document %0% doit être déplacé - a été choisi comme racine de votre contenu, cliquez sur 'ok' ci-dessous. - Aucun noeud choisi, choisissez s'il vous plait un noeud dans la liste ci-dessus avant de cliquer sur 'ok'. - Le noeud actuel n'est pas autorisé dans le noeud choisi à cause de son type + Choisissez ci-dessous l'endroit où le document %0% doit être déplacé + a été choisi comme racine de votre nouveau contenu, cliquez sur 'ok' ci-dessous. + Aucun noeud n'a encore été choisi, veuillez choisir un noeud dans la liste ci-dessus avant de cliquer sur 'ok'. + Le noeud actuel n'est pas autorisé sous le noeud choisi à cause de son type Le noeud actuel ne peut pas être déplacé dans une de ses propres sous-pages Le noeud actuel ne peut pas exister à la racine - L'action n'est pas autorisée car vous n'avez pas les droits sur un ou plus des noeuds enfants. - Relier les items copiés à l'original + L'action n'est pas autorisée car vous n'avez pas les droits suffisants sur un ou plusieurs noeuds enfants. + Relier les éléments copiés à l'original - Editer vos notifications pour %0% + Editez vos notifications pour %0% - Hi %0%

    + + Hello %0%

    Ceci est un email automatique pour vous informer que la tâche '%1%' a été executée sur la page '%2%' @@ -626,11 +746,11 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à

    -

    Update summary:

    +

    Résumé de la mise à jour :

    %6%
    @@ -638,71 +758,79 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à

    Bonne journée !

    - Le Robot Umbraco vous salue + Avec les salutations du Robot Umbraco

    ]]>
    La notification [%0%] à propos de %1% a été executée sur %2% Notifications - localisez le package. Les packages Umbraco ont généralement une extension .umb ou .zip. + Choisissez un package sur votre ordinateur en cliquant sur le bouton Parcourir
    + et localisez le package. Les packages Umbraco ont généralement une extension ".umb" ou ".zip". ]]>
    Auteur - Demon + Démo Documentation Meta data du package Nom du package - Le package ne contient aucun éléments -
    - Vous pouvez supprimer tranquillement le package de votre installation en cliquant sur "Désinstaller" ci-dessous.]]>
    - Aucune mises à jour disponibles - Options de package + Le package ne contient aucun élément +
    + Vous pouvez supprimer tranquillement ce package de votre installation en cliquant sur "Désinstaller le package" ci-dessous.]]>
    + Aucune mise à jour disponible + Options du package Package readme - Package repository + Repository des packages Confirmation de désinstallation - Package was uninstalled + Le package a été désinstallé Le package a été désinstallé avec succès - Désintaller le package - - Remarque : tous les documents, media etc dépendants des éléments que vous supprimerez, arrêteront de fonctionner, ce qui peut provoquer une instabilité du système, - désinstallez avec prudence. En cas de doute, contactez l'auteur du package.]]> + Désinstaller le package + + Remarque : tous les documents, media etc. dépendant des éléments que vous supprimez vont cesser de fonctionner, ce qui peut provoquer une instabilité du système, + désinstallez donc avec prudence. En cas de doute, contactez l'auteur du package.]]> Télécharger la mise à jour depuis le repository Mettre à jour le package Instructions de mise à jour - Il y a une mise à jour disponible pour ce package. Vous pouvez la télécharger directement depuis le repository. - Version de package - Historique des version de package + Il y a une mise à jour disponible pour ce package. Vous pouvez la télécharger directement depuis le repository des packages Umbraco. + Version du package + Historique des versions du package Voir le site internet du package + Package déjà installé + Ce package ne peut pas être installé, il nécessite au minimum la version Umbraco %0% + Désinstallation... + Téléchargement... + Import... + Installation... + Redémarrage, veuillez patienter... + Terminé, votre navigateur va être rafraîchi, veuillez patienter... Coller en conservant le formatage (non recommandé) - Le texte que vous tentez de coller contient des caractères spéciaux ou de formatage. Cela peut être dû à une copie d'un texte de Microsoft Word. Umbraco peut supprimer les caractères spéciaux et le formatage automatiquement, de manière à ce que le texte collé soit plus utilisable pour le Web. - Coller en tant que texte brut sans formatage - Coller, mais supprimer le formatage (recommendé) + Le texte que vous tentez de coller contient des caractères spéciaux ou du formatage. Cela peut être dû à une copie d'un texte depuis Microsoft Word. Umbraco peut supprimer automatiquement les caractères spéciaux et le formatage, de manière à ce que le texte collé convienne mieux pour le Web. + Coller en tant que texte brut sans aucun formatage + Coller, mais supprimer le formatage (recommandé) Protection basée sur les rôles via les groupes de membres Umbraco.]]> - l'authentification basée sur les rôles.]]> + l'authentification basée sur les rôles.]]> Page d'erreur - Utilisé quand les gens sont connectés, mais n'ont pas accès + Utilisé pour les personnes connectées, mais qui n'ont pas accès Choisissez comment restreindre l'accès à cette page %0% est maintenant protégée Protection supprimée de %0% Page de connexion - Choisissez la page qui a le formulaire de login + Choisissez la page qui contient le formulaire de connexion Supprimer la protection - Choisissez la page qui contient le formulaire de login et les messages d'erreur - Piochez les roles qui ont accès à cette page - Définissez l'identifiant et mot de passe pour cette page + Choisissez les pages qui contiennent le formulaire de connexion et les messages d'erreur + Choisissez les rôles qui ont accès à cette page + Définissez l'identifiant et le mot de passe pour cette page Protection utilisateur unique - Si vous souhaitez simplement mettre en place une protection par identifiant et mot de passe + Si vous souhaitez mettre en place une protection simple utilisant un identifiant et un mot de passe uniques @@ -710,44 +838,47 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à %0% n'a pas pu être publié car cet élément est programmé pour être publié bientôt. ]]> + - Inclure les pages enfants non publiées + Inclure les pages enfant non publiées Publication en cours - veuillez patienter... - %0% sur %1% des pages ont été publiées... + %0% pages sur %1% ont été publiées... %0% a été publié %0% et ses pages enfants ont été publiées - Publier %0% et ses pages enfants - ok pour publier %0% et le rendre ainsi accessible publiquement.

    - Vous pouvez publier cette page et ses sous pages en cochant publier tous les enfants ci-dessous. + Publier %0% et toutes ses pages enfant + Publier pour publier %0% et la rendre ainsi accessible publiquement.

    + Vous pouvez publier cette page et toutes ses sous-pages en cochant Inclure les pages enfant non pubiées ci-dessous. ]]>
    - Vous n'avez configuré aucune couleurs approuvées + Vous n'avez configuré aucune couleur approuvée - Ajouter un lien externe - Ajouter un lien interne - Ajouter + introduire un lien externe + choisir une page interne Légende - Page interne - URL - Descendre - Monter + Lien Ouvrir dans une nouvelle fenêtre - Supprimer le lien + introduisez la légende à afficher + Introduiser le lien + + + Réinitialiser Version actuelle - Le texte en Rouge signifit qu'il a été supprimé de la version choisie, vert signifie ajouté]]> - Le document est passé à une version antérieure + Le texte en Rouge signifie qu'il a été supprimé de la version choisie, vert signifie ajouté]]> + Le document a été restauré à une version antérieure Ceci affiche la version choisie en tant que HTML, si vous souhaitez voir les différences entre les deux versions en même temps, utilisez la vue différentielle Revenir à Choisissez une version @@ -765,16 +896,24 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Medias Membres Newsletters - Paramètres + Configuration Statistiques Traduction Utilisateurs Aide + Formulaires + Analytics + + + aller à + Rubriques d'aided pour + Chapitres vidéo pour + Les meilleurs tutoriels vidéo Umbraco - Template par défaut + Modèle par défaut Clé de dictionnaire - Pour importer un type de document, trouvez le fichier ".udt" sur votre ordinateur en cliquant sur le bouton "Parcourir" et cliquez sur "Importer" (une confirmation vous sera demandé à l'écran d'après) + Pour importer un type de document, trouvez le fichier ".udt" sur votre ordinateur en cliquant sur le bouton "Parcourir" et cliquez sur "Importer" (une confirmation vous sera demandée à l'écran suivant) Titre du nouvel onglet Type de noeud Type @@ -784,22 +923,29 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Onglet Titre de l'onglet Onglets - Type de contenu master activé + Type de contenu de base activé Ce type de contenu utilise - en tant que type de contenu master, les onglets du type de contenu master ne sont pas affichés et peuvent seulement être modifiés dans le type de contenu master lui-même. - Aucune propriétés définies dans cet onglet. Cliquez sur le lien "Ajouter une nouvelle propriété" en haut pour créer une nouvelle propriété. - Type de contenu parent - Créer le template correspondant - + en tant que type de contenu de base. Les onglets du type de contenu de base ne sont pas affichés et peuvent seulement être modifiés à partir du type de contenu de base lui-même. + Aucune propriété définie dans cet onglet. Cliquez sur le lien "Ajouter une nouvelle propriété" en-haut pour créer une nouvelle propriété. + Type de contenu de base + Créer le modèle correspondant + Ajouter une icône + - Sort order - Creation date + Ordre de tri + Date de création Tri achevé. - Faites glisser les différents éléments ci-dessous vers le haut ou le bas pour définir comment ils doivent être triés. Ou cliquez sur les entêtes de colonne pour trier la collection complète d'éléments + Faites glisser les différents éléments vers le haut ou vers le bas pour définir la manière dont ils doivent être organisés. Ou cliquez sur les entêtes de colonnes pour trier la collection complète d'éléments
    Ne fermez pas cette fenêtre durant le tri.]]>
    - La publication a été annulée par un extension tierce. + Validation + Les erreurs de validation doivent être corrigées avant de pouvoir sauvegarder l'élément + Echec + Permissions utilisateur insuffisantes, l'opération n'a pas pu être complétée + Annulation + L'opération a été annulée par une extension tierce + La publication a été annulée par une extension tierce. Le type de propriété existe déjà Type de propriété créé Type de données : %1%]]> @@ -807,33 +953,35 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Type de documet sauvegardé Onglet créé Onglet supprimé - Onglet d'ID : %0% supprimé + Onglet avec l'ID : %0% supprimé Feuille de style non sauvegardée Feuille de style sauvegardée Feuille de style sauvegardée sans erreurs - Type de données sauvegardée - Element de dictionnaire sauvegardé + Type de données sauvegardé + Elément de dictionnaire sauvegardé La publication a échoué car la page parent n'est pas publiée Contenu publié et visible sur le site - Content sauvegardé - N'oubliez pas de publier pour rendre les changements visibles + Contenu sauvegardé + N'oubliez pas de publier pour rendre les modifications visibles Envoyer pour approbation - Les changements ont été envoyés pour approbation + Les modifications ont été envoyées pour approbation Media sauvegardé Media sauvegardé sans erreurs Membre sauvegardé - Propriété de feuille de style sauvegardé - Feuille de style sauvegardé - Template sauvegardé - Erreur lors de la sauvegarde de l'utilisateur + Propriété de feuille de style sauvegardée + Feuille de style sauvegardée + Modèle sauvegardé + Erreur lors de la sauvegarde de l'utilisateur (consultez les logs) Utilisateur sauvegardé Type d'utilisateur sauvegardé Fichier non sauvegardé Le fichier n'a pas pu être sauvegardé. Vérifiez les permissions de fichier. Fichier sauvegardé Fichier sauvegardé sans erreurs - Langage sauvegardé + Langue sauvegardée + Type de média sauvegardé + Type de membre sauvegardé Le script Python n'a pas été sauvegardé Le script Python n'a pas été sauvegardé à cause d'erreurs Le script Python a été sauvegardé @@ -846,30 +994,35 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Le XSLT contenait une erreur Le XSLT n'a pas pu être sauvegardé, vérifiez les permissions de fichier Le XSLT a été sauvegardé - Aucune erreurs dans le XSLT + Aucune erreur dans le XSLT Contenu publié Vue partielle sauvegardée Vue partielle sauvegardée sans erreurs ! Vue partielle non sauvegardée Une erreur est survenue lors de la sauvegarde du fichier. - + Vue script sauvegardée + Vue script sauvegardée sans erreur ! + Vue script non sauvegardée + Une erreur est survenue lors de la sauvegarde du fichier. + Une erreur est survenue lors de la sauvegarde du fichier. + - Utilise la synthaxe CSS. Ex : h1, .redHeader, .blueTex + Utilise la syntaxe CSS. Ex : h1, .redHeader, .blueTex Editer la feuille de style Editer la propriété de feuille de style - Nommer pour identifier la propriété dans le Rich Text Editor + Donner un nom pour identifier la propriété dans le Rich Text Editor Prévisualiser Styles - Editer le modèle template + Editer le modèle Insérer une zone de contenu Insérer un placeholder de zone de contenu Insérer un élément de dictionnaire - Insert Macro - Insert umbraco page field - Modèle master - Guide rapide aux tags des modèles Umbraco + Insérer une Macro + Insérer un champ de la page Umbraco + Modèle de base + Guide rapide concernant les tags des modèles Umbraco Modèle @@ -877,40 +1030,113 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Choisissez une mise en page Ajouter une ligne Ajouter du contenu - Contenu goutte + Supprimer le contenu Paramètres appliqués - Ce contenu est pas autorisée ici - Ce contenu est permis ici + Ce contenu n'est pas autorisé ici + Ce contenu est autorisé ici Cliquez pour intégrer - Cliquez pour insérer l'image + Cliquez pour insérer une image Légende de l'image... - Ecrire ici... + Ecrivez ici... - Layouts Grid - Layouts sont la superficie totale de travail pour l'éditeur de grille, en général, vous avez seulement besoin d'une ou deux configurations différentes - Ajouter Grid Layout - Ajustez la mise en page en définissant la largeur des colonnes et ajouter des sections supplémentaires - Configurations des lignes - Les lignes sont des cellules prédéfinies disposées horizontalement - Ajouter une configuration de la ligne - Ajustez la ligne en réglant la largeur des cellules et en ajoutant des cellules supplémentaires + Mises en pages de la Grid + Les mises en pages représentent la surface de travail globale pour l'éditeur de grille, en général, vous n'avez seulement besoin que d'une ou deux mises en pages différentes + Ajouter une mise en page de grille + Ajustez la mise en page en définissant la largeur des colonnes et en ajoutant des sections supplémentaires + Configurations des rangées + Les rangées sont des cellules prédéfinies disposées horizontalement + Ajouter une configuration de rangée + Ajustez la rangée en réglant la largeur des cellules et en ajoutant des cellules supplémentaires Colonnes Nombre total combiné de colonnes dans la configuration de la grille Paramètres - Configurer quels paramètres éditeurs peuvent changer + Configurez les paramètres qui peuvent être modifiés par les éditeurs - Modes - Configurer ce style éditeurs peuvent changer + + Styles + Configurez les effets de style qui peuvent être modifiés par les éditeurs - Les réglages seulement économiser si la configuration du json saisi est valide + Les paramètres ne seront sauvegardés que si la configuration json saisie est valide Autoriser tous les éditeurs - Autoriser toutes les configurations de lignes + Autoriser toutes les configurations de rangées + Configurer comme défaut + Choisir en plus + Choisir le défaut + ont été ajoutés + + + Compositions + Vous n'avez pas ajouté d'onglet + Ajouter un nouvel onglet + Ajouter un autre onglet + Hérité de + Ajouter une propriété + Label requis + + Activer la vue en liste + Configure l'élément de contenu de manière à afficher ses éléments enfants sous forme d'une liste que l'on peut trier et filtrer, les enfants ne seront pas affichés dans l'arborescence + + Modèles autorisés + Sélectionnez les modèles que les éditeurs sont autorisés à utiliser pour du contenu de ce type. + Autorisé comme racine + Autorisez les éditeurs à créer du contenu de ce type à la racine de l'arborescence de contenu. + Oui - autoriser du contenu de ce type à la racine + + Types de noeuds enfants autorisés + Autorisez la création de contenu des types spécifiés sous le contenu de ce type-ci + + Choisissez les noeuds enfants + Hériter des onglets et propriétés d'un type de document existant. De nouveaux onglets seront ajoutés au type de document actuel, ou fusionnés s'il existe un onglet avec un nom sililaire. + Ce type de contenu est utilisé dans une composition, et ne peut donc pas être lui-même un composé. + Il n'y a pas de type de contenu disponible à utiliser dans une composition. + + Editeurs disponibles + Réutiliser + Configuration de l'éditeur + + Configuration + + Oui, supprimer + + a été déplacé en-dessous + a été copié en-dessous + Sélectionnez le répertoire à déplacer + Sélectionnez le répertoire à copier + dans l'arborescence ci-dessous + + Tous les types de document + Tous les documents + Tous les éléments media + + utilisant ce type de document seront supprimés définitivement, veuillez confirmer que vous souhaitez les supprimer également. + utilisant ce type de media seront supprimés définitivement, veuillez confirmer que vous souhaitez les supprimer également. + utilisant ce type de membre seront supprimés définitivement, veuillez confirmer que vous souhaitez les supprimer également + + et tous les documents utilisant ce type + et tous les éléments media utilisant ce type + et tous les membres utilisant ce type + + utilisant cet éditeur seront mis à jour avec la nouvelle configuration + + Le membre peut éditer + Afficher dans le profil du membre + l'onglet n'a pas d'ordonnancement + + + + Création des modèles + ceci peut prendre un certain temps, ne vous inquiétez pas + Les modèles ont été générés + Les modèles n'ont pas pu être générés + La génération des modèles a échoué, veuillez consulter les erreurs dans le log Umbraco + + Champ alternatif Texte alternatif @@ -924,67 +1150,68 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Formater comme une date Encoder en HTML Remplacera les caractères spéciaux par leur équivalent HTML. - Sera insérer après la valeur du champ - Sera inséré après la valeur du champ + Sera inséré après la valeur du champ + Sera inséré avant la valeur du champ Minuscules Aucun - Inserer après le champ - Inserer après le champ - Recursif - Supprimer les balises paragraphes - Supprimera tous les &lt;P&gt; + Insérer après le champ + Insérer avant le champ + Récursif + Supprimer les balises de paragraphes + Supprimera toute balise &lt;P&gt; au début et à la fin du texte Champs standards Majuscules - Encode en URL - Formatera les caractères spéciaux de manière à ce qu'ils soient utilisés dans une URL - Sera seulement utilisé quand toutes les valeurs ci-dessous seront vides - Ce champ sera utilisé seulement si le champ primaire est vide - Yes, with time. Separator: + Encode pour URL + Formatera les caractères spéciaux de manière à ce qu'ils soient reconnus dans une URL + Sera seulement utilisé si toutes les valeurs des champs ci-dessus sont vides + Ce champ sera utilisé seulement si le champ initial est vide + Oui, avec l'heure. Séparateur: Tâches qui vous sont assignées - vous sont assignées. Pour voir une vue détaillée incluant les commentaires, cliquez sur "Details" ou juste le nom de la page. - Vous pouvez télécharger la format au format XML en cliquant sur le lien "Télécharger XML".
    - Pour terminer une tâche de traduction, allez sur Details, puis cliquer sur le bouton "Terminer tâche". + vous sont assignées. Pour voir un aperçu détaillé incluant les commentaires, cliquez sur "Détails" ou juste sur le nom de la page. + Vous pouvez aussi télécharger la page au format XML en cliquant sur le lien "Télécharger XML".
    + Pour clôturer une tâche de traduction, allez sur Détails, puis cliquez sur le bouton "Terminer la tâche". ]]>
    - Terminer tâche + Terminer la tâche Détails - Télécharger toutes les traductions au format XML + Télécharger toutes les tâches de traductions au format XML Télécharger XML Télécharger la DTD XML Champs Inclure les pages enfants [%0%] tâches de traductions pour %1% - Aucun utilisateurs traducteurs trouvés. Vous devez créer un utilisateur traducteur avant d'envoyer votre contenu pour traduction - Tâches que vous avez créé - créées par vous. Pour voir une vue détaillée incluant les commentaires, - cliquez sur "Détails" ou juste le nom de la page. Vous pouvez aussi télécharger la page au format XML en cliquant sur le lien "Télécharger XML". - Pour terminer une tâche de traduction, allez sur Details, puis cliquer sur le bouton "Terminer tâche". + Aucun utilisateur traducteur trouvé. Veuillez créer un utilisateur traducteur avant d'envoyer du contenu pour traduction + Tâches que vous avez créées + que vous avez créées. Pour voir un aperçu détaillé incluant les commentaires, + cliquez sur "Détails" ou juste sur le nom de la page. Vous pouvez aussi télécharger la page au format XML en cliquant sur le lien "Télécharger XML". + Pour clôturer une tâche de traduction, allez sur Détails, puis cliquez sur le bouton "Terminer tâche". ]]> - La page '%0%' a été envoyé pour traduction + La page '%0%' a été envoyée pour traduction + Veuillez choisir la langue dans laquelle le contenu doit être traduit Envoyer la page '%0%' pour traduction Assignée par - Tâches ouvertures + Tâches ouvertes Nombre total de mots Traduire en Traduction complétée. - Vous pouvez prévisualiser les pages que vous avez traduites, en cliquant ci-dessous. Si la page originale est trouvée, vous aurez la comparaison entre les deux pages. - Traductio échouée, il semble que le fichier XML soit corrompu + Vous pouvez prévisualiser les pages que vous avez traduites en cliquant ci-dessous. Si la page originale est trouvée, vous verrez une comparaison entre les deux pages. + Traduction échouée, il se pourrait que fichier XML soit corrompu Options de traduction Traducteur Uploader le fichier de traduction XML @@ -993,20 +1220,21 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Navigateur de cache Corbeille Packages créés - Typesde données + Types de données Dictionnaire Packages installés - Installer un skin + Installer une skin Installer un starter kit - Langages + Langues Installer un package local Macros - Types de médias + Types de média Membres Groupes de membres Rôles Types de membres Types de documents + Types de relations Packages Packages Fichiers Python @@ -1018,53 +1246,184 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Feuilles de style Modèles Fichiers XSLT + Analytique - Nouvelle mise à jour prête - %0% est prêt, cliquez ici pour télécharger + Nouvelle mise à jour disponible + %0% est disponible, cliquez ici pour télécharger Aucune connexion au serveur - Erreur lors de la recherche de mises à jour. Vérifiez la stack trace pour obtenir plus d'informations sur l'erreur. + Erreur lors de la recherche de mises à jour. Veuillez vérifier le stack trace pour obtenir plus d'informations sur l'erreur. Administrateur Champ catégorie Changer le mot de passe - Changez votre mot de passe + Nouveau mot de passe Confirmez votre nouveau mot de passe - Vous pouvez changer votre mot de passe d'accès à Umbraco en remplissant le formulaire ci-dessous puis en cliquant sur le bouton "Changer le mot de passe" + Vous pouvez changer votre mot de passe d'accès au Back Office Umbraco en remplissant le formulaire ci-dessous puis en cliquant sur le bouton "Changer le mot de passe" Canal de contenu Champ description Désactiver l'utilisateur Type de document Editeur Champ extrait - Langage + Langue Identifiant - Noeud de départ dans la librarie de médias + Noeud de départ dans la librarie de média Sections Désactiver l'accès Umbraco + Ancien mot de passe Mot de passe Réinitialiser le mot de passe - Your password has been changed! - Confirmez s'il vous plait votre nouveau mot de passe - Entrez votre nouveau mot de passe + Votre mot de passe a été modifié! + Veuillez confirmer votre nouveau mot de passe + Introduisez votre nouveau mot de passe Votre nouveau mot de passe ne peut être vide ! Mot de passe actuel Mot de passe actuel invalide - Il y avait une différence entre le nouveau mot de passe et le mot de passe confirmé. Veuillez réessayer - Le mot de passe confirmé ne match pas le nouveau mot de passe saisi - Remplacer les permissions des noeuds enfants - Vous modifiez actuellement les permissions pour les pages : - Choisissez les pages pour lesquelles modifier les permissions + Il y a une différence entre le nouveau mot de passe et le mot de passe confirmé. Veuillez réessayer. + Le mot de passe confirmé ne correspond pas au nouveau mot de passe saisi! + Remplacer les permissions sur les noeuds enfants + Vous êtes en train de modifiez les permissions pour les pages : + Choisissez les pages dont les permissions doivent être modifiées Rechercher tous les enfants Noeud de départ du contenu Nom d'utilisateur Permissions utilisateur Type d'utilisateur - Types d'utilisateur + Types d'utilisateurs Rédacteur + Traducteur + Modifier Votre profil Votre historique récent La session expire dans + + Validation + Valider comme email + Valider comme nombre + Valider comme Url + ...ou introduisez une validation spécifique + Champ obligatoire + + + + La valeur est égale à la valeur recommandée : '%0%'. + La valeur du XPath '%2%' a été fixée à '%1%' dans le fichier de configuration '%3%'. + La valeur attendue pour '%2%' dans le fichier de configuration '%3%' est '%1%', mais la valeur trouvée est '%0%'. + La valeur inattendue '%0%' a été trouvée pour '%2%' dans le fichier de configuration '%3%'. + + + Custom errors est fixé à la valeur '%0%'. + Custom errors est pour la moment fixé à la valeur '%0%'. Il est recommandé de le fixer la valeur à '%1%' avant la mise en ligne. + Custom errors a été rectifié avec succès à la valeur '%0%'. + + MacroErrors est fixé à la valeur '%0%'. + MacroErrors est fixé à la valeur '%0%', ce qui empêchera certaines ou même toutes les pages de votre site de se charger complètement en cas d'erreur dans les macros. La rectification de ceci fixera la valeur à '%1%'. + MacroErrors est maintenant fixé à la valeur '%0%'. + + + Try Skip IIS Custom Errors est fixé à la valeur '%0%' et vous utilisez IIS version '%1%'. + Try Skip IIS Custom Errors est actuellement fixé à '%0%'. Il est recommandé de fixer la valeur à '%1%' pour votre version IIS (%2%). + Try Skip IIS Custom Errors a été rectifié avec succès à la valeur '%0%'. + + + Le fichier n'existe pas : '%0%'. + '%0%' dans le fichier config '%1%'.]]> + Une erreur est survenue, consultez le log pour voir l'erreur complète : %0%. + + Total XML : %0%, Total : %1% + Total XML : %0%, Total : %1% + Total XML : %0%, Total publié : %1% + + Erreur de validation du certificat : '%0%' + Erreur en essayant de contacter l'URL %0% - '%1%' + Vous êtes actuellement %0% à voir le site via le schéma HTTPS. + La valeur appSetting 'umbracoUseSSL' est fixée à 'false' dans votre fichier web.config. Une fois que vous donnerez accès à ce site en utilisant le schéma HTTPS, cette valeur devra être mise à 'true'. + La valeur appSetting 'umbracoUseSSL' est fixée à '%0%' dans votre fichier web.config, vos cookies sont %1% marqués comme étant sécurisés. + Impossible de mettre à jour la configuration 'umbracoUseSSL' dans votre fichier web.config. Erreur : %0% + + + Activer HTTPS + Fixe la configuration 'umbracoSSL' à 'true' dans la section appSettings du fichier web.config. + La configuration appSetting 'umbracoUseSSL' est maintenant fixée à 'true' dans votre fichier web.config, vos cookies seront marqués comme étant sécurisés. + + Corriger + Impossible de corriger une vérification avec un type de comparaison 'ShouldNotEqual'. + Impossible de corriger une vérification avec un type de comparaison 'ShouldEqual' avec une valeur spécifiée. + La valeur de correction n'est pas fournie. + + Le mode de compilation Debug est désactivé. + Le mode de compilation Debug a été désactivé avec succès. + Le mode de compilation Debug est actuellement activé. Il est recommandé de désactiver ce paramètre avant la mise en ligne. + + Le mode tracing est désactivé. + Le mode tracing est actuellement activé. Il est recommandé de désactiver cette configuration avant la mise en ligne. + Le mode tracing a été désactivé avec succès. + + Tous les répertoires ont les configurations de permissions adéquates. + + %0%.]]> + %0%. Aucune action n'est requise s'il n'y a pas de nécessité d'y écrire.]]> + + Tous les fichiers ont les configurations de permissions adéquates. + + %0%.]]> + %0%. Aucune action n'est requise s'il n'y a pas de nécessité d'y écrire.]]> + + X-Frame-Options, utilisé pour contrôler si un site peut être intégré dans un autre via IFRAME, a été trouvé.]]> + X-Frame-Options , utilisé pour contrôler si un site peut être intégré dans un autre via IFRAME, n'a pas été trouvé.]]> + Configurez le Header dans le fichier Config + Ajoute une valeur dans la section httpProtocol/customHeaders du fichier web.config afin d'éviter que le site ne soit intégré dans d'autres sites via IFRAME. + Une configuration générant un header qui empêche l'intégration du site par d'autres sites via IFRAME a été ajoutée à votre fichier web.config. + Impossible de modifier le fichier web.config. Erreur : %0% + + + %0%.]]> + Aucun header révélant des informations à propos de la technologie du site web n'a été trouvé. + + La section system.net/mailsettings n'a pas pu être trouvée dans le fichier Web.config. + Dans la section system.net/mailsettings du fichier Web.config, le "host" n'est pas configuré. + La configuration SMTP est correcte et le service fonctionne comme prévu. + Le serveur SMTP configuré avec le host '%0%' et le port '%1%' n'a pas pu être contacté. Veuillez vérifier et vous assurer que la configuration SMTP est correcte dans la section system.net/mailsettings du fichier Web.config. + + %0%.]]> + %0%.]]> + + + Désactiver URL tracker + Activer URL tracker + URL original + Redirigé Vers + Aucune redirection n'a été créée + Lorsqu'une page publiée est renommée ou déplacée, une redirection sera automatiquement créée vers la nouvelle page. + Supprimer + Etes-vous certain(e) de vouloir supprimer la redirection de '%0%' vers '%1%'? + Redirection d'URL supprimée. + Erreur lors de la suppression de la redirection d'URL. + Etes-vous certain(e) de vouloir désactiver le URL tracker? + URL tracker est maintenant désactivé. + Erreur lors de la désactivation de l'URL tracker, plus d'information disponible dans votre fichier log. + URL tracker est maintenant activé. + Erreur lors de l'activation de l'URL tracker, plus d'information disponible dans votre fichier log. + diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml index beced6eb79..d01caaa315 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml @@ -275,19 +275,12 @@ クリックすると画像がフルサイズで表示されます 項目の選択 キャッシュされている項目の表示 - フォルダーの作成... - + フォルダーの作成... オリジナルに関連付ける フレンドリーなコミュニティ - ページへリンク - リンク ドキュメントを新しいウィンドウまたはタブで開く - リンク ドキュメントをウィンドウ全文表示で開く - 親フレームでリンク ドキュメントを開く - メディアへリンク - メディアの選択 アイコンの選択 アイテムの選択 @@ -296,19 +289,14 @@ コンテンツの選択 メンバーの選択 メンバー グループの選択 - このマクロのパラメーターはありません - 外部ログイン プロバイダー 例外の詳細 スタックトレース Inner Exception - 次をリンク: 次をリンク解除: - アカウント - エディターの選択 diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml index 97dcf9ef38..312e863c36 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml @@ -15,8 +15,8 @@ Deaktywuj Opróżnij kosz Eksportuj typ dokumentu - TRANSLATE ME: 'Export to .NET' - TRANSLATE ME: 'Export to .NET' + Ekspo .NET' + Eksportuj do .NET' Importuj typ dokumentu Importuj zbiór Edytuj na stronie @@ -118,7 +118,7 @@ Przeglądaj swoją stronę - TRANSLATE ME: '- Hide' + - Ukryj Jeśli Umbraco się nie otwiera, prawdopodbnie musisz zezwolić tej stronie na otwieranie wyskakujących okienek zostało otwarte w nowym oknie Restartuj @@ -168,7 +168,7 @@ Proszę zaznaczyć, aby potwierdzić usunięcie %0% elementów. Jesteś pewny? Jesteś pewny? - TRANSLATE ME: 'Cut' + Wytnij Edytuj element słownika Edytuj język Wstaw link wewnętrzny @@ -183,7 +183,7 @@ Link wewnętrzny: Kiedy używasz odnośników lokalnych, wstaw znak "#" na początku linku Otworzyć w nowym oknie? - TRANSLATE ME: 'Macro Settings' + Ustawienia Makra To makro nie posiada żadnych właściwości, które można edytować Wklej Edytuj Uprawnienia dla @@ -192,7 +192,7 @@ Usunięcie elementów z kosza powoduje ich trwałe i nieodwracalne skasowanie regexlib.com aktulanie nie jest dostępny, na co nie mamy wpływu. Bardzo przepraszamy za te utrudnienia.]]> Przeszukaj dla wyrażeń regularnych aby dodać regułę sprawdzającą do formularza. Np. 'email' 'url' - TRANSLATE ME: 'Remove Macro' + Usuń Makro Pole wymagane Strona została przeindeksowana Cache strony zostało odświeżone. Cała opublikowana zawartość jest teraz aktualna. Natomiast cała nieopublikowana zawartość ciągle nie jest widoczna @@ -222,7 +222,7 @@ Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]> Dodaj wartość Typ bazydanych - TRANSLATE ME: 'Data Editor GUID' + Edytor GUID Renderuj kontrolkę Przyciski Włącz ustawienia zaawansowane dla @@ -235,7 +235,7 @@ Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]>
    Dane zostały zapisane, lecz wystąpiły błędy które musisz poprawić przed publikacją strony: Bieżący dostawca Membership nie obsługuje zmiany hasła (EnablePasswordRetrieval musi mieć wartość true) - TRANSLATE ME: '%0% already exists' + %0% już istnieje Wystąpiły błędy: Wystąpiły błędy: Hasło powinno mieć minimum %0% znaków, i zawierać co najmniej %1% niealfanumeryczny znak @@ -308,7 +308,7 @@ Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]>
    Język układ Ładowanie - TRANSLATE ME: 'Locked' + Zablokowany Zaloguj Wyloguj Wyloguj @@ -332,7 +332,7 @@ Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]>
    Kosz Pozostało Zmień nazwę - TRANSLATE ME: 'Renew' + Odnów Ponów próbę Uprawnienia Szukaj @@ -341,7 +341,7 @@ Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]> Pokaż stronę "wyślij" Rozmiar Sortuj - Submit + Zatwierdź Typ Szukaj W górę @@ -356,8 +356,8 @@ Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]> Witaj... Szerokość Tak - Reorder - I am done reordering + Zmień kolejność + Kolejność została zmieniona Kolor tła @@ -786,7 +786,7 @@ Miłego dnia!]]> Administrator Pole kategorii - TRANSLATE ME: 'Change Your Password' + Zmień hasło! TRANSLATE ME: 'You can change your password for accessing the Umbraco Back Office by filling out the form below and click the 'Change Password' button' Zawartość Opis @@ -800,10 +800,10 @@ Miłego dnia!]]> Sekcje Wyłącz dostęp do Umbraco Hasło - TRANSLATE ME: 'Your password has been changed!' - TRANSLATE ME: 'Please confirm the new password' - TRANSLATE ME: 'Enter your new password' - TRANSLATE ME: 'Your new password cannot be blank!' + Twoje hasło zostało zmienione! + Proszę potwierdź nowe hasło! + Wprowadź nowe hasło + Nowe hasło nie może byc puste! TRANSLATE ME: 'There was a difference between the new password and the confirmed password. Please try again!' TRANSLATE ME: 'The confirmed password doesn't match the new password!' Zastąp prawa dostępu dla węzłów potomnych diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml index 75c5630678..255bf62d5d 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml @@ -340,18 +340,11 @@ Выберите элемент Просмотр элемента кэша Создать папку... - Связать с оригиналом Самое дружелюбное сообщество - Ссылка на страницу - Открывает документ по ссылке в новом окне или вкладке браузера - Открывает документ по ссылке в полноэкранном режиме - Открывает документ по ссылке в родительском фрейме - Ссылка на медиа-файл - Выбрать медиа Выбрать значок Выбрать элемент @@ -360,19 +353,14 @@ Выбрать содержимое Выбрать участника Выбрать группу участников - Это макрос без параметров - Провайдеры аутентификации Подробное сообщение об ошибке Трассировка стека Внутренняя ошибка - Связать Разорвать связь - учетную запись - Выбрать редактор @@ -380,6 +368,12 @@ Ниже Вы можете указать различные переводы данной статьи словаря '%0%'
    Добавить другие языки можно, воспользовавшись пунктом 'Языки' в меню слева ]]> Название языка (культуры) + Редактировать элемент (ключ) словаря + + + Допустим как корневой @@ -655,7 +649,7 @@ Медиа - всего в XML: %0%, всего: %1%Б с ошибками: %2% Содержимое - всего в XML: %0%, всего опубликовано: %1%, с ошибками: %2% - Сертификат Вашего сайта отмечен как проверенный. + Сертификат Вашего веб-сайта отмечен как проверенный. Ошибка проверки сертификата: '%0%' Ошибка проверки адреса URL %0% - '%1%' Сейчас Вы %0% просматриваете сайт, используя протокол HTTPS. diff --git a/src/Umbraco.Web.UI/umbraco/create/User.ascx b/src/Umbraco.Web.UI/umbraco/create/User.ascx index deb139c557..3a00811776 100644 --- a/src/Umbraco.Web.UI/umbraco/create/User.ascx +++ b/src/Umbraco.Web.UI/umbraco/create/User.ascx @@ -22,7 +22,7 @@ ControlToValidate="Email" ValidateEmptyText="false" OnServerValidate="EmailExistsCheck">
    diff --git a/src/Umbraco.Web.UI/umbraco_client/Application/UmbracoApplicationActions.js b/src/Umbraco.Web.UI/umbraco_client/Application/UmbracoApplicationActions.js index 46b7a15e48..4c9017e159 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Application/UmbracoApplicationActions.js +++ b/src/Umbraco.Web.UI/umbraco_client/Application/UmbracoApplicationActions.js @@ -281,7 +281,7 @@ Umbraco.Application.Actions = function() { actionRePublish: function() { /// - UmbClientMgr.openModalWindow('dialogs/republish.aspx?rnd=' + this._utils.generateRandom(), 'Republishing entire site', true, 450, 210); + UmbClientMgr.openModalWindow('dialogs/republish.aspx?rnd=' + this._utils.generateRandom(), uiKeys['actions_republish'], true, 450, 210); }, actionAssignDomain: function() { diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 08140f9c66..6604aee507 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -531,8 +531,17 @@ namespace Umbraco.Web.Editors { var mediaType = Constants.Conventions.MediaTypes.File; - if (UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes.Contains(ext)) - mediaType = Constants.Conventions.MediaTypes.Image; + if (result.FormData["contentTypeAlias"] == Constants.Conventions.MediaTypes.AutoSelect) + { + if (UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes.Contains(ext)) + { + mediaType = Constants.Conventions.MediaTypes.Image; + } + } + else + { + mediaType = result.FormData["contentTypeAlias"]; + } //TODO: make the media item name "nice" since file names could be pretty ugly, we have // string extensions to do much of this but we'll need: diff --git a/src/Umbraco.Web/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs b/src/Umbraco.Web/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs index 83275450e4..cf279bf3f8 100644 --- a/src/Umbraco.Web/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs +++ b/src/Umbraco.Web/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security [HealthCheck( "92ABBAA2-0586-4089-8AE2-9A843439D577", "Excessive Headers", - Description = "Checks to see if your site is revealing information in it's headers that gives away unnecessary details about the technology used to build and host it.", + Description = "Checks to see if your site is revealing information in its headers that gives away unnecessary details about the technology used to build and host it.", Group = "Security")] public class ExcessiveHeadersCheck : HealthCheck { diff --git a/src/Umbraco.Web/HtmlStringUtilities.cs b/src/Umbraco.Web/HtmlStringUtilities.cs index 5ba1d17f4e..24a643b5b0 100644 --- a/src/Umbraco.Web/HtmlStringUtilities.cs +++ b/src/Umbraco.Web/HtmlStringUtilities.cs @@ -211,6 +211,13 @@ namespace Umbraco.Web if (!lengthReached && currentTextLength >= length) { + // if the last character added was the first of a two character unicode pair, add the second character + if (Char.IsHighSurrogate((char)ic)) + { + var lowSurrogate = tr.Read(); + outputtw.Write((char)lowSurrogate); + } + // Reached truncate limit. if (addElipsis) { diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index b7a6ac1f4a..e179159e7c 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -6,7 +6,6 @@ using System.Web; using System.Web.Mvc; using System.Web.Routing; using AutoMapper; -using umbraco; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Mapping; @@ -29,38 +28,18 @@ namespace Umbraco.Web.Models.Mapping //FROM IContent TO ContentItemDisplay config.CreateMap() - .ForMember( - dto => dto.Owner, - expression => expression.ResolveUsing(new OwnerResolver())) - .ForMember( - dto => dto.Updater, - expression => expression.ResolveUsing(new CreatorResolver())) - .ForMember( - dto => dto.Icon, - expression => expression.MapFrom(content => content.ContentType.Icon)) - .ForMember( - dto => dto.ContentTypeAlias, - expression => expression.MapFrom(content => content.ContentType.Alias)) - .ForMember( - dto => dto.ContentTypeName, - expression => expression.MapFrom(content => content.ContentType.Name)) - .ForMember( - dto => dto.IsContainer, - expression => expression.MapFrom(content => content.ContentType.IsContainer)) - .ForMember(display => display.IsChildOfListView, expression => expression.Ignore()) - .ForMember( - dto => dto.Trashed, - expression => expression.MapFrom(content => content.Trashed)) - .ForMember( - dto => dto.PublishDate, - expression => expression.MapFrom(content => GetPublishedDate(content, applicationContext))) - .ForMember( - dto => dto.TemplateAlias, expression => expression.MapFrom(content => content.Template.Alias)) - .ForMember( - dto => dto.HasPublishedVersion, - expression => expression.MapFrom(content => content.HasPublishedVersion)) - .ForMember( - dto => dto.Urls, + .ForMember(display => display.Owner, expression => expression.ResolveUsing(new OwnerResolver())) + .ForMember(display => display.Updater, expression => expression.ResolveUsing(new CreatorResolver())) + .ForMember(display => display.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) + .ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) + .ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name)) + .ForMember(display => display.IsContainer, expression => expression.MapFrom(content => content.ContentType.IsContainer)) + .ForMember(display => display.IsChildOfListView, expression => expression.Ignore()) + .ForMember(display => display.Trashed, expression => expression.MapFrom(content => content.Trashed)) + .ForMember(display => display.PublishDate, expression => expression.MapFrom(content => GetPublishedDate(content, applicationContext))) + .ForMember(display => display.TemplateAlias, expression => expression.MapFrom(content => content.Template.Alias)) + .ForMember(display => display.HasPublishedVersion, expression => expression.MapFrom(content => content.HasPublishedVersion)) + .ForMember(display => display.Urls, expression => expression.MapFrom(content => UmbracoContext.Current == null ? new[] {"Cannot generate urls without a current Umbraco Context"} @@ -74,47 +53,28 @@ namespace Umbraco.Web.Models.Mapping .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService))) .ForMember(display => display.AllowedActions, expression => expression.ResolveUsing( new ActionButtonsResolver(new Lazy(() => applicationContext.Services.UserService)))) - .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService, + .AfterMap((content, display) => AfterMap(content, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService, applicationContext.Services.ContentTypeService)); //FROM IContent TO ContentItemBasic config.CreateMap>() - .ForMember( - dto => dto.Owner, - expression => expression.ResolveUsing(new OwnerResolver())) - .ForMember( - dto => dto.Updater, - expression => expression.ResolveUsing(new CreatorResolver())) - .ForMember( - dto => dto.Icon, - expression => expression.MapFrom(content => content.ContentType.Icon)) - .ForMember( - dto => dto.Trashed, - expression => expression.MapFrom(content => content.Trashed)) - .ForMember( - dto => dto.HasPublishedVersion, - expression => expression.MapFrom(content => content.HasPublishedVersion)) - .ForMember( - dto => dto.ContentTypeAlias, - expression => expression.MapFrom(content => content.ContentType.Alias)) - .ForMember(display => display.Alias, expression => expression.Ignore()); + .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) + .ForMember(dto => dto.Updater, expression => expression.ResolveUsing(new CreatorResolver())) + .ForMember(dto => dto.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) + .ForMember(dto => dto.Trashed, expression => expression.MapFrom(content => content.Trashed)) + .ForMember(dto => dto.HasPublishedVersion, expression => expression.MapFrom(content => content.HasPublishedVersion)) + .ForMember(dto => dto.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) + .ForMember(dto => dto.Alias, expression => expression.Ignore()); //FROM IContent TO ContentItemDto config.CreateMap>() - .ForMember( - dto => dto.Owner, - expression => expression.ResolveUsing(new OwnerResolver())) - .ForMember( - dto => dto.HasPublishedVersion, - expression => expression.MapFrom(content => content.HasPublishedVersion)) - .ForMember(display => display.Updater, expression => expression.Ignore()) - .ForMember(display => display.Icon, expression => expression.Ignore()) - .ForMember(display => display.Alias, expression => expression.Ignore()); - - + .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) + .ForMember(dto => dto.HasPublishedVersion, expression => expression.MapFrom(content => content.HasPublishedVersion)) + .ForMember(dto => dto.Updater, expression => expression.Ignore()) + .ForMember(dto => dto.Icon, expression => expression.Ignore()) + .ForMember(dto => dto.Alias, expression => expression.Ignore()); } - /// /// Maps the generic tab with custom properties for content /// @@ -123,7 +83,7 @@ namespace Umbraco.Web.Models.Mapping /// /// /// - private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService, + private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText, IContentTypeService contentTypeService) { //map the IsChildOfListView (this is actually if it is a descendant of a list view!) @@ -151,7 +111,6 @@ namespace Umbraco.Web.Models.Mapping display.IsChildOfListView = ancesctorListView != null; } } - //map the tree node url if (HttpContext.Current != null) @@ -160,9 +119,9 @@ namespace Umbraco.Web.Models.Mapping var url = urlHelper.GetUmbracoApiService(controller => controller.GetTreeNode(display.Id.ToString(), null)); display.TreeNodeUrl = url; } - + //fill in the template config to be passed to the template drop down. - var templateItemConfig = new Dictionary { { "", "Choose..." } }; + var templateItemConfig = new Dictionary {{"", "Choose..."}}; foreach (var t in content.ContentType.AllowedTemplates .Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false)) { @@ -173,7 +132,7 @@ namespace Umbraco.Web.Models.Mapping { TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService, localizedText); } - + var properties = new List { new ContentPropertyDisplay @@ -183,26 +142,26 @@ namespace Umbraco.Web.Models.Mapping Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName), View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View }, - new ContentPropertyDisplay + new ContentPropertyDisplay { Alias = string.Format("{0}releasedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = localizedText.Localize("content/releaseDate"), Value = display.ReleaseDate.HasValue ? display.ReleaseDate.Value.ToIsoString() : null, //Not editible for people without publish permission (U4-287) - View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View, + View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View, Config = new Dictionary { {"offsetTime", "1"} } //TODO: Fix up hard coded datepicker - } , + }, new ContentPropertyDisplay { Alias = string.Format("{0}expiredate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Label = localizedText.Localize("content/unpublishDate"), Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null, //Not editible for people without publish permission (U4-287) - View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View, + View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View, Config = new Dictionary { {"offsetTime", "1"} @@ -246,21 +205,21 @@ namespace Umbraco.Web.Models.Mapping var docTypeLink = string.Format("#/settings/documenttypes/edit/{0}", currentDocumentTypeId); //Replace the doc type property - var docTypeProp = genericProperties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); - docTypeProp.Value = new List + var docTypeProperty = genericProperties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); + docTypeProperty.Value = new List { new { linkText = currentDocumentTypeName, url = docTypeLink, - target = "_self", icon = "icon-item-arrangement" + target = "_self", + icon = "icon-item-arrangement" } }; //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor - docTypeProp.View = "urllist"; + docTypeProperty.View = "urllist"; } }); - } /// @@ -305,13 +264,13 @@ namespace Umbraco.Web.Models.Mapping var svc = _userService.Value; var permissions = svc.GetPermissions( - //TODO: This is certainly not ideal usage here - perhaps the best way to deal with this in the future is - // with the IUmbracoContextAccessor. In the meantime, if used outside of a web app this will throw a null - // refrence exception :( - UmbracoContext.Current.Security.CurrentUser, - // Here we need to do a special check since this could be new content, in which case we need to get the permissions - // from the parent, not the existing one otherwise permissions would be coming from the root since Id is 0. - source.HasIdentity ? source.Id : source.ParentId) + //TODO: This is certainly not ideal usage here - perhaps the best way to deal with this in the future is + // with the IUmbracoContextAccessor. In the meantime, if used outside of a web app this will throw a null + // refrence exception :( + UmbracoContext.Current.Security.CurrentUser, + // Here we need to do a special check since this could be new content, in which case we need to get the permissions + // from the parent, not the existing one otherwise permissions would be coming from the root since Id is 0. + source.HasIdentity ? source.Id : source.ParentId) .FirstOrDefault(); return permissions == null @@ -319,6 +278,5 @@ namespace Umbraco.Web.Models.Mapping : permissions.AssignedPermissions.Where(x => x.Length == 1).Select(x => x.ToUpperInvariant()[0]); } } - } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs index d13da67e1f..c3f9412401 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Web; using System.Web.Mvc; using System.Web.Routing; using AutoMapper; -using umbraco; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; @@ -29,22 +25,12 @@ namespace Umbraco.Web.Models.Mapping { //FROM IMedia TO MediaItemDisplay config.CreateMap() - .ForMember( - dto => dto.Owner, - expression => expression.ResolveUsing(new OwnerResolver())) - .ForMember( - dto => dto.Icon, - expression => expression.MapFrom(content => content.ContentType.Icon)) - .ForMember( - dto => dto.ContentTypeAlias, - expression => expression.MapFrom(content => content.ContentType.Alias)) + .ForMember(display => display.Owner, expression => expression.ResolveUsing(new OwnerResolver())) + .ForMember(display => display.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) + .ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) .ForMember(display => display.IsChildOfListView, expression => expression.Ignore()) - .ForMember( - dto => dto.Trashed, - expression => expression.MapFrom(content => content.Trashed)) - .ForMember( - dto => dto.ContentTypeName, - expression => expression.MapFrom(content => content.ContentType.Name)) + .ForMember(display => display.Trashed, expression => expression.MapFrom(content => content.Trashed)) + .ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name)) .ForMember(display => display.Properties, expression => expression.Ignore()) .ForMember(display => display.TreeNodeUrl, expression => expression.Ignore()) .ForMember(display => display.Notifications, expression => expression.Ignore()) @@ -53,39 +39,29 @@ namespace Umbraco.Web.Models.Mapping .ForMember(display => display.Updater, expression => expression.Ignore()) .ForMember(display => display.Alias, expression => expression.Ignore()) .ForMember(display => display.IsContainer, expression => expression.Ignore()) - .ForMember(member => member.HasPublishedVersion, expression => expression.Ignore()) + .ForMember(display => display.HasPublishedVersion, expression => expression.Ignore()) .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService))) .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService, applicationContext.ProfilingLogger.Logger)); //FROM IMedia TO ContentItemBasic config.CreateMap>() - .ForMember( - dto => dto.Owner, - expression => expression.ResolveUsing(new OwnerResolver())) - .ForMember( - dto => dto.Icon, - expression => expression.MapFrom(content => content.ContentType.Icon)) - .ForMember( - dto => dto.Trashed, - expression => expression.MapFrom(content => content.Trashed)) - .ForMember( - dto => dto.ContentTypeAlias, - expression => expression.MapFrom(content => content.ContentType.Alias)) - .ForMember(x => x.Published, expression => expression.Ignore()) - .ForMember(x => x.Updater, expression => expression.Ignore()) - .ForMember(x => x.Alias, expression => expression.Ignore()) - .ForMember(member => member.HasPublishedVersion, expression => expression.Ignore()); + .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) + .ForMember(dto => dto.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) + .ForMember(dto => dto.Trashed, expression => expression.MapFrom(content => content.Trashed)) + .ForMember(dto => dto.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) + .ForMember(dto => dto.Published, expression => expression.Ignore()) + .ForMember(dto => dto.Updater, expression => expression.Ignore()) + .ForMember(dto => dto.Alias, expression => expression.Ignore()) + .ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore()); //FROM IMedia TO ContentItemDto config.CreateMap>() - .ForMember( - dto => dto.Owner, - expression => expression.ResolveUsing(new OwnerResolver())) - .ForMember(x => x.Published, expression => expression.Ignore()) - .ForMember(x => x.Updater, expression => expression.Ignore()) - .ForMember(x => x.Icon, expression => expression.Ignore()) - .ForMember(x => x.Alias, expression => expression.Ignore()) - .ForMember(member => member.HasPublishedVersion, expression => expression.Ignore()); + .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) + .ForMember(dto => dto.Published, expression => expression.Ignore()) + .ForMember(dto => dto.Updater, expression => expression.Ignore()) + .ForMember(dto => dto.Icon, expression => expression.Ignore()) + .ForMember(dto => dto.Alias, expression => expression.Ignore()) + .ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore()); } private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText, ILogger logger) @@ -155,8 +131,28 @@ namespace Umbraco.Web.Models.Mapping genericProperties.Add(link); } - TabsAndPropertiesResolver.MapGenericProperties(media, display, localizedText, genericProperties); - } + TabsAndPropertiesResolver.MapGenericProperties(media, display, localizedText, genericProperties, properties => + { + if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null + && UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) + { + var mediaTypeLink = string.Format("#/settings/mediatypes/edit/{0}", media.ContentTypeId); + //Replace the doctype property + var docTypeProperty = properties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); + docTypeProperty.Value = new List + { + new + { + linkText = media.ContentType.Name, + url = mediaTypeLink, + target = "_self", + icon = "icon-item-arrangement" + } + }; + docTypeProperty.View = "urllist"; + } + }); + } } } diff --git a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs index 050fe3c726..edb44d36ce 100644 --- a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs @@ -11,7 +11,6 @@ using Umbraco.Core.Models.Mapping; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; -using umbraco; using System.Linq; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Security; @@ -29,10 +28,10 @@ namespace Umbraco.Web.Models.Mapping //FROM MembershipUser TO MediaItemDisplay - used when using a non-umbraco membership provider config.CreateMap() .ConvertUsing(user => - { - var member = Mapper.Map(user); - return Mapper.Map(member); - }); + { + var member = Mapper.Map(user); + return Mapper.Map(member); + }); //FROM MembershipUser TO IMember - used when using a non-umbraco membership provider config.CreateMap() @@ -62,23 +61,13 @@ namespace Umbraco.Web.Models.Mapping //FROM IMember TO MediaItemDisplay config.CreateMap() - .ForMember( - dto => dto.Owner, - expression => expression.ResolveUsing(new OwnerResolver())) - .ForMember( - dto => dto.Icon, - expression => expression.MapFrom(content => content.ContentType.Icon)) - .ForMember( - dto => dto.ContentTypeAlias, - expression => expression.MapFrom(content => content.ContentType.Alias)) - .ForMember( - dto => dto.ContentTypeName, - expression => expression.MapFrom(content => content.ContentType.Name)) + .ForMember(display => display.Owner, expression => expression.ResolveUsing(new OwnerResolver())) + .ForMember(display => display.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) + .ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) + .ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name)) .ForMember(display => display.Properties, expression => expression.Ignore()) - .ForMember(display => display.Tabs, - expression => expression.ResolveUsing(new MemberTabsAndPropertiesResolver(applicationContext.Services.TextService))) - .ForMember(display => display.MemberProviderFieldMapping, - expression => expression.ResolveUsing(new MemberProviderFieldMappingResolver())) + .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new MemberTabsAndPropertiesResolver(applicationContext.Services.TextService))) + .ForMember(display => display.MemberProviderFieldMapping, expression => expression.ResolveUsing(new MemberProviderFieldMappingResolver())) .ForMember(display => display.MembershipScenario, expression => expression.ResolveUsing(new MembershipScenarioMappingResolver(new Lazy(() => applicationContext.Services.MemberTypeService)))) .ForMember(display => display.Notifications, expression => expression.Ignore()) @@ -90,31 +79,21 @@ namespace Umbraco.Web.Models.Mapping .ForMember(display => display.Trashed, expression => expression.Ignore()) .ForMember(display => display.IsContainer, expression => expression.Ignore()) .ForMember(display => display.TreeNodeUrl, expression => expression.Ignore()) - .ForMember(member => member.HasPublishedVersion, expression => expression.Ignore()) + .ForMember(display => display.HasPublishedVersion, expression => expression.Ignore()) .AfterMap((member, display) => MapGenericCustomProperties(applicationContext.Services.MemberService, member, display, applicationContext.Services.TextService)); //FROM IMember TO MemberBasic config.CreateMap() - .ForMember( - dto => dto.Owner, - expression => expression.ResolveUsing(new OwnerResolver())) - .ForMember( - dto => dto.Icon, - expression => expression.MapFrom(content => content.ContentType.Icon)) - .ForMember( - dto => dto.ContentTypeAlias, - expression => expression.MapFrom(content => content.ContentType.Alias)) - .ForMember( - dto => dto.Email, - expression => expression.MapFrom(content => content.Email)) - .ForMember( - dto => dto.Username, - expression => expression.MapFrom(content => content.Username)) - .ForMember(display => display.Trashed, expression => expression.Ignore()) - .ForMember(x => x.Published, expression => expression.Ignore()) - .ForMember(x => x.Updater, expression => expression.Ignore()) - .ForMember(x => x.Alias, expression => expression.Ignore()) - .ForMember(member => member.HasPublishedVersion, expression => expression.Ignore()); + .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) + .ForMember(dto => dto.Icon, expression => expression.MapFrom(content => content.ContentType.Icon)) + .ForMember(dto => dto.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) + .ForMember(dto => dto.Email, expression => expression.MapFrom(content => content.Email)) + .ForMember(dto => dto.Username, expression => expression.MapFrom(content => content.Username)) + .ForMember(dto => dto.Trashed, expression => expression.Ignore()) + .ForMember(dto => dto.Published, expression => expression.Ignore()) + .ForMember(dto => dto.Updater, expression => expression.Ignore()) + .ForMember(dto => dto.Alias, expression => expression.Ignore()) + .ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore()); //FROM MembershipUser TO MemberBasic config.CreateMap() @@ -123,41 +102,31 @@ namespace Umbraco.Web.Models.Mapping .ForMember(member => member.CreateDate, expression => expression.MapFrom(user => user.CreationDate)) .ForMember(member => member.UpdateDate, expression => expression.MapFrom(user => user.LastActivityDate)) .ForMember(member => member.Key, expression => expression.MapFrom(user => user.ProviderUserKey.TryConvertTo().Result.ToString("N"))) - .ForMember( - dto => dto.Owner, - expression => expression.UseValue(new UserBasic {Name = "Admin", UserId = 0})) - .ForMember( - dto => dto.Icon, - expression => expression.UseValue("icon-user")) + .ForMember(member => member.Owner, expression => expression.UseValue(new UserBasic {Name = "Admin", UserId = 0})) + .ForMember(member => member.Icon, expression => expression.UseValue("icon-user")) .ForMember(member => member.Name, expression => expression.MapFrom(user => user.UserName)) - .ForMember( - dto => dto.Email, - expression => expression.MapFrom(content => content.Email)) - .ForMember( - dto => dto.Username, - expression => expression.MapFrom(content => content.UserName)) + .ForMember(member => member.Email, expression => expression.MapFrom(content => content.Email)) + .ForMember(member => member.Username, expression => expression.MapFrom(content => content.UserName)) .ForMember(member => member.Properties, expression => expression.Ignore()) .ForMember(member => member.ParentId, expression => expression.Ignore()) .ForMember(member => member.Path, expression => expression.Ignore()) .ForMember(member => member.SortOrder, expression => expression.Ignore()) .ForMember(member => member.AdditionalData, expression => expression.Ignore()) - .ForMember(x => x.Published, expression => expression.Ignore()) - .ForMember(x => x.Updater, expression => expression.Ignore()) - .ForMember(dto => dto.Trashed, expression => expression.Ignore()) - .ForMember(x => x.Alias, expression => expression.Ignore()) - .ForMember(x => x.ContentTypeAlias, expression => expression.Ignore()) + .ForMember(member => member.Published, expression => expression.Ignore()) + .ForMember(member => member.Updater, expression => expression.Ignore()) + .ForMember(member => member.Trashed, expression => expression.Ignore()) + .ForMember(member => member.Alias, expression => expression.Ignore()) + .ForMember(member => member.ContentTypeAlias, expression => expression.Ignore()) .ForMember(member => member.HasPublishedVersion, expression => expression.Ignore()); //FROM IMember TO ContentItemDto config.CreateMap>() - .ForMember( - dto => dto.Owner, - expression => expression.ResolveUsing(new OwnerResolver())) - .ForMember(x => x.Published, expression => expression.Ignore()) - .ForMember(x => x.Updater, expression => expression.Ignore()) - .ForMember(x => x.Icon, expression => expression.Ignore()) - .ForMember(x => x.Alias, expression => expression.Ignore()) - .ForMember(member => member.HasPublishedVersion, expression => expression.Ignore()) + .ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver())) + .ForMember(dto => dto.Published, expression => expression.Ignore()) + .ForMember(dto => dto.Updater, expression => expression.Ignore()) + .ForMember(dto => dto.Icon, expression => expression.Ignore()) + .ForMember(dto => dto.Alias, expression => expression.Ignore()) + .ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore()) //do no map the custom member properties (currently anyways, they were never there in 6.x) .ForMember(dto => dto.Properties, expression => expression.ResolveUsing(new MemberDtoPropertiesValueResolver())); } @@ -232,8 +201,28 @@ namespace Umbraco.Web.Models.Mapping } }; + TabsAndPropertiesResolver.MapGenericProperties(member, display, localizedText, genericProperties, properties => + { + if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null + && UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) + { + var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", member.ContentTypeId); - TabsAndPropertiesResolver.MapGenericProperties(member, display, localizedText, genericProperties); + //Replace the doctype property + var docTypeProperty = properties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); + docTypeProperty.Value = new List + { + new + { + linkText = member.ContentType.Name, + url = memberTypeLink, + target = "_self", + icon = "icon-item-arrangement" + } + }; + docTypeProperty.View = "urllist"; + } + }); //check if there's an approval field var provider = membersProvider as global::umbraco.providers.members.UmbracoMembershipProvider; @@ -246,7 +235,6 @@ namespace Umbraco.Web.Models.Mapping prop.Value = 1; } } - } /// @@ -255,6 +243,7 @@ namespace Umbraco.Web.Models.Mapping /// /// /// + /// /// /// /// If the membership provider installed is the umbraco membership provider, then we will allow changing the username, however if @@ -264,11 +253,11 @@ namespace Umbraco.Web.Models.Mapping internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, MemberDisplay display, ILocalizedTextService localizedText) { var prop = new ContentPropertyDisplay - { - Alias = string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = localizedText.Localize("login"), - Value = display.Username - }; + { + Alias = string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = localizedText.Localize("login"), + Value = display.Username + }; var scenario = memberService.GetMembershipScenario(); @@ -321,8 +310,8 @@ namespace Umbraco.Web.Models.Mapping var exclude = defaultProps.Select(x => x.Value.Alias).ToArray(); return source.Properties - .Where(x => exclude.Contains(x.Alias) == false) - .Select(Mapper.Map); + .Where(x => exclude.Contains(x.Alias) == false) + .Select(Mapper.Map); } } @@ -375,7 +364,7 @@ namespace Umbraco.Web.Models.Mapping } else { - var umbracoProvider = (IUmbracoMemberTypeMembershipProvider)provider; + var umbracoProvider = (IUmbracoMemberTypeMembershipProvider) provider; //This is kind of a hack because a developer is supposed to be allowed to set their property editor - would have been much easier // if we just had all of the membeship provider fields on the member table :( @@ -389,8 +378,6 @@ namespace Umbraco.Web.Models.Mapping return result; } - - } } @@ -413,8 +400,8 @@ namespace Umbraco.Web.Models.Mapping } var memberType = _memberTypeService.Value.Get(Constants.Conventions.MemberTypes.DefaultAlias); return memberType != null - ? MembershipScenario.CustomProviderWithUmbracoLink - : MembershipScenario.StandaloneCustomProvider; + ? MembershipScenario.CustomProviderWithUmbracoLink + : MembershipScenario.StandaloneCustomProvider; } } @@ -438,7 +425,7 @@ namespace Umbraco.Web.Models.Mapping } else { - var umbracoProvider = (IUmbracoMemberTypeMembershipProvider)provider; + var umbracoProvider = (IUmbracoMemberTypeMembershipProvider) provider; return new Dictionary { @@ -447,10 +434,7 @@ namespace Umbraco.Web.Models.Mapping {Constants.Conventions.Member.Comments, umbracoProvider.CommentPropertyTypeAlias} }; } - - } } - } } \ No newline at end of file diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs index 884138a9b4..83a4606d19 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs @@ -16,7 +16,9 @@ using umbraco; using System.Linq; using umbraco.BusinessLogic; using umbraco.presentation.preview; +using Umbraco.Core.Services; using GlobalSettings = umbraco.GlobalSettings; +using Task = System.Threading.Tasks.Task; namespace Umbraco.Web.PublishedCache.XmlPublishedCache { @@ -26,6 +28,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly RoutesCache _routesCache = new RoutesCache(!UnitTesting); + private DomainHelper _domainHelper; + + private DomainHelper GetDomainHelper(IDomainService domainService) + { + return _domainHelper ?? (_domainHelper = new DomainHelper(domainService)); + } + // for INTERNAL, UNIT TESTS use ONLY internal RoutesCache RoutesCache { get { return _routesCache; } } @@ -99,6 +108,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // - non-colliding, adds one complete "by route" lookup, only on the first time a url is computed (then it's cached anyways) // - colliding, adds one "by route" lookup, the first time the url is computed, then one dictionary looked each time it is computed again // assuming no collisions, the impact is one complete "by route" lookup the first time each url is computed + // + // U4-9121 - this lookup is too expensive when computing a large amount of urls on a front-end (eg menu) + // ... thinking about moving the lookup out of the path into its own async task, so we are not reporting errors + // in the back-office anymore, but at least we are not polluting the cache + // instead, refactored DeterminedIdByRoute to stop using XPath, with a 16x improvement according to benchmarks + // will it be enough? + var loopId = preview ? 0 : _routesCache.GetNodeId(route); // might be cached already in case of collision if (loopId == 0) { @@ -130,62 +146,141 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var pos = route.IndexOf('/'); var path = pos == 0 ? route : route.Substring(pos); var startNodeId = pos == 0 ? 0 : int.Parse(route.Substring(0, pos)); - IEnumerable vars; - - var xpath = CreateXpathQuery(startNodeId, path, hideTopLevelNode, out vars); //check if we can find the node in our xml cache - var content = GetSingleByXPath(umbracoContext, preview, xpath, vars == null ? null : vars.ToArray()); + var id = NavigateRoute(umbracoContext, preview, startNodeId, path, hideTopLevelNode); + if (id > 0) return GetById(umbracoContext, preview, id); // if hideTopLevelNodePath is true then for url /foo we looked for /*/foo // but maybe that was the url of a non-default top-level node, so we also // have to look for /foo (see note in ApplyHideTopLevelNodeFromPath). - if (content == null && hideTopLevelNode && path.Length > 1 && path.IndexOf('/', 1) < 0) + if (hideTopLevelNode && path.Length > 1 && path.IndexOf('/', 1) < 0) { - xpath = CreateXpathQuery(startNodeId, path, false, out vars); - content = GetSingleByXPath(umbracoContext, preview, xpath, vars == null ? null : vars.ToArray()); + var id2 = NavigateRoute(umbracoContext, preview, startNodeId, path, false); + if (id2 > 0) return GetById(umbracoContext, preview, id2); } - return content; + return null; + } + + private int NavigateRoute(UmbracoContext umbracoContext, bool preview, int startNodeId, string path, bool hideTopLevelNode) + { + var xml = GetXml(umbracoContext, preview); + XmlElement elt; + + // empty path + if (path == string.Empty || path == "/") + { + if (startNodeId > 0) + { + elt = xml.GetElementById(startNodeId.ToString(CultureInfo.InvariantCulture)); + return elt == null ? -1 : startNodeId; + } + + elt = null; + var min = int.MaxValue; + foreach (XmlElement e in xml.DocumentElement.ChildNodes) + { + var sortOrder = int.Parse(e.GetAttribute("sortOrder")); + if (sortOrder < min) + { + min = sortOrder; + elt = e; + } + } + return elt == null ? -1 : int.Parse(elt.GetAttribute("id")); + } + + // non-empty path + elt = startNodeId <= 0 + ? xml.DocumentElement + : xml.GetElementById(startNodeId.ToString(CultureInfo.InvariantCulture)); + if (elt == null) return -1; + + var urlParts = path.Split(SlashChar, StringSplitOptions.RemoveEmptyEntries); + + if (hideTopLevelNode && startNodeId <= 0) + { + foreach (XmlElement e in elt.ChildNodes) + { + var id = NavigateElementRoute(e, urlParts); + if (id > 0) return id; + } + return -1; + } + + return NavigateElementRoute(elt, urlParts); + } + + private static bool UseLegacySchema + { + get { return UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema; } + } + + private int NavigateElementRoute(XmlElement elt, string[] urlParts) + { + var found = true; + var i = 0; + while (found && i < urlParts.Length) + { + found = false; + foreach (XmlElement child in elt.ChildNodes) + { + var noNode = UseLegacySchema + ? child.Name != "node" + : child.GetAttributeNode("isDoc") == null; + if (noNode) continue; + if (child.GetAttribute("urlName") != urlParts[i]) continue; + + found = true; + elt = child; + break; + } + i++; + } + return found ? int.Parse(elt.GetAttribute("id")) : -1; } string DetermineRouteById(UmbracoContext umbracoContext, bool preview, int contentId) { - var node = GetById(umbracoContext, preview, contentId); - if (node == null) - return null; + var elt = GetXml(umbracoContext, preview).GetElementById(contentId.ToString(CultureInfo.InvariantCulture)); + if (elt == null) return null; - var domainHelper = new DomainHelper(umbracoContext.Application.Services.DomainService); + var domainHelper = GetDomainHelper(umbracoContext.Application.Services.DomainService); // walk up from that node until we hit a node with a domain, // or we reach the content root, collecting urls in the way var pathParts = new List(); - var n = node; - var hasDomains = domainHelper.NodeHasDomains(n.Id); - while (hasDomains == false && n != null) // n is null at root + var eltId = int.Parse(elt.GetAttribute("id")); + var eltParentId = int.Parse(((XmlElement) elt.ParentNode).GetAttribute("id")); + var e = elt; + var id = eltId; + var hasDomains = domainHelper.NodeHasDomains(id); + while (hasDomains == false && id != -1) { // get the url - var urlName = n.UrlName; + var urlName = e.GetAttribute("urlName"); pathParts.Add(urlName); // move to parent node - n = n.Parent; - hasDomains = n != null && domainHelper.NodeHasDomains(n.Id); + e = (XmlElement) e.ParentNode; + id = int.Parse(e.GetAttribute("id")); + hasDomains = id != -1 && domainHelper.NodeHasDomains(id); } // no domain, respect HideTopLevelNodeFromPath for legacy purposes - if (hasDomains == false && global::umbraco.GlobalSettings.HideTopLevelNodeFromPath) - ApplyHideTopLevelNodeFromPath(umbracoContext, node, pathParts); + if (hasDomains == false && GlobalSettings.HideTopLevelNodeFromPath) + ApplyHideTopLevelNodeFromPath(umbracoContext, eltId, eltParentId, pathParts); // assemble the route pathParts.Reverse(); var path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc - var route = (n == null ? "" : n.Id.ToString(CultureInfo.InvariantCulture)) + path; + var route = (id == -1 ? "" : id.ToString(CultureInfo.InvariantCulture)) + path; return route; } - static void ApplyHideTopLevelNodeFromPath(UmbracoContext umbracoContext, IPublishedContent node, IList pathParts) + static void ApplyHideTopLevelNodeFromPath(UmbracoContext umbracoContext, int nodeId, int parentId, IList pathParts) { // in theory if hideTopLevelNodeFromPath is true, then there should be only once // top-level node, or else domains should be assigned. but for backward compatibility @@ -195,12 +290,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // "/foo" fails (looking for "/*/foo") we try also "/foo". // this does not make much sense anyway esp. if both "/foo/" and "/bar/foo" exist, but // that's the way it works pre-4.10 and we try to be backward compat for the time being - if (node.Parent == null) + if (parentId == -1) { var rootNode = umbracoContext.ContentCache.GetByRoute("/", true); if (rootNode == null) throw new Exception("Failed to get node at /."); - if (rootNode.Id == node.Id) // remove only if we're the default node + if (rootNode.Id == nodeId) // remove only if we're the default node pathParts.RemoveAt(pathParts.Count - 1); } else @@ -217,12 +312,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { public int Version { get; private set; } - public static string Root { get { return "/root"; } } public string RootDocuments { get; private set; } - public string DescendantDocumentById { get; private set; } - public string ChildDocumentByUrlName { get; private set; } - public string ChildDocumentByUrlNameVar { get; private set; } - public string RootDocumentWithLowestSortOrder { get; private set; } public XPathStringsDefinition(int version) { @@ -233,19 +323,11 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // legacy XML schema case 0: RootDocuments = "/root/node"; - DescendantDocumentById = "//node [@id={0}]"; - ChildDocumentByUrlName = "/node [@urlName='{0}']"; - ChildDocumentByUrlNameVar = "/node [@urlName=${0}]"; - RootDocumentWithLowestSortOrder = "/root/node [not(@sortOrder > ../node/@sortOrder)][1]"; break; // default XML schema as of 4.10 case 1: RootDocuments = "/root/* [@isDoc]"; - DescendantDocumentById = "//* [@isDoc and @id={0}]"; - ChildDocumentByUrlName = "/* [@isDoc and @urlName='{0}']"; - ChildDocumentByUrlNameVar = "/* [@isDoc and @urlName=${0}]"; - RootDocumentWithLowestSortOrder = "/root/* [@isDoc and not(@sortOrder > ../* [@isDoc]/@sortOrder)][1]"; break; default: @@ -421,84 +503,6 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache static readonly char[] SlashChar = new[] { '/' }; - protected string CreateXpathQuery(int startNodeId, string path, bool hideTopLevelNodeFromPath, out IEnumerable vars) - { - string xpath; - vars = null; - - if (path == string.Empty || path == "/") - { - // if url is empty - if (startNodeId > 0) - { - // if in a domain then use the root node of the domain - xpath = string.Format(XPathStringsDefinition.Root + XPathStrings.DescendantDocumentById, startNodeId); - } - else - { - // if not in a domain - what is the default page? - // let's say it is the first one in the tree, if any -- order by sortOrder - - // but! - // umbraco does not consistently guarantee that sortOrder starts with 0 - // so the one that we want is the one with the smallest sortOrder - // read http://stackoverflow.com/questions/1128745/how-can-i-use-xpath-to-find-the-minimum-value-of-an-attribute-in-a-set-of-elemen - - // so that one does not work, because min(@sortOrder) maybe 1 - // xpath = "/root/*[@isDoc and @sortOrder='0']"; - - // and we can't use min() because that's XPath 2.0 - // that one works - xpath = XPathStrings.RootDocumentWithLowestSortOrder; - } - } - else - { - // if url is not empty, then use it to try lookup a matching page - var urlParts = path.Split(SlashChar, StringSplitOptions.RemoveEmptyEntries); - var xpathBuilder = new StringBuilder(); - int partsIndex = 0; - List varsList = null; - - if (startNodeId == 0) - { - if (hideTopLevelNodeFromPath) - xpathBuilder.Append(XPathStrings.RootDocuments); // first node is not in the url - else - xpathBuilder.Append(XPathStringsDefinition.Root); - } - else - { - xpathBuilder.AppendFormat(XPathStringsDefinition.Root + XPathStrings.DescendantDocumentById, startNodeId); - // always "hide top level" when there's a domain - } - - while (partsIndex < urlParts.Length) - { - var part = urlParts[partsIndex++]; - if (part.Contains('\'') || part.Contains('"')) - { - // use vars, escaping gets ugly pretty quickly - varsList = varsList ?? new List(); - var varName = string.Format("var{0}", partsIndex); - varsList.Add(new XPathVariable(varName, part)); - xpathBuilder.AppendFormat(XPathStrings.ChildDocumentByUrlNameVar, varName); - } - else - { - xpathBuilder.AppendFormat(XPathStrings.ChildDocumentByUrlName, part); - - } - } - - xpath = xpathBuilder.ToString(); - if (varsList != null) - vars = varsList.ToArray(); - } - - return xpath; - } - #endregion #region Detached diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs index da1ff94fe1..f3cc101b21 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs @@ -226,7 +226,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // the media from the service, first var media = ApplicationContext.Current.Services.MediaService.GetById(id); - if (media == null) return null; // not found, ok + if (media == null || media.Trashed) return null; // not found, ok // so, the media was not found in Examine's index *yet* it exists, which probably indicates that // the index is corrupted. Or not up-to-date. Log a warning, but only once, and only if seeing the diff --git a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs index 41f4ae232a..1d142158e3 100644 --- a/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs +++ b/src/Umbraco.Web/Trees/LegacyTreeDataConverter.cs @@ -254,7 +254,7 @@ namespace Umbraco.Web.Trees return Attempt.Succeed( new LegacyUrlAction( "dialogs/republish.aspx?rnd=" + DateTime.UtcNow.Ticks, - "Republishing entire site")); + ui.GetText("actions", "republish"))); case "UmbClientMgr.appActions().actionAssignDomain()": return Attempt.Succeed( new LegacyUrlAction( @@ -415,4 +415,4 @@ namespace Umbraco.Web.Trees } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/umbraco.presentation/helper.cs b/src/Umbraco.Web/umbraco.presentation/helper.cs index 0d133fee66..2bee9d1e3a 100644 --- a/src/Umbraco.Web/umbraco.presentation/helper.cs +++ b/src/Umbraco.Web/umbraco.presentation/helper.cs @@ -95,12 +95,14 @@ namespace umbraco { var attributeValueSplit = (attributeValue).Split(','); + attributeValueSplit = attributeValueSplit.Select(x => x.Trim()).ToArray(); + // before proceeding, we don't want to process anything here unless each item starts/ends with a [ ] // this is because the attribute value could actually just be a json array like [1,2,3] which we don't want to parse // // however, the last one can be a literal, must take care of this! // so here, don't check the last one, which can be just anything - if (attributeValueSplit.Take(attributeValueSplit.Length - 1).All(x => + if (attributeValueSplit.Take(attributeValueSplit.Length - 1).All(x => //must end with [ x.EndsWith("]") && //must start with [ and a special char diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/cruds.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/cruds.aspx.cs index 1634fd370f..3808547db1 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/cruds.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/cruds.aspx.cs @@ -34,7 +34,7 @@ namespace umbraco.dialogs protected void Page_Load(object sender, EventArgs e) { Button1.Text = ui.Text("update"); - pane_form.Text = "Set permissions for the page " + _node.Text; + pane_form.Text = ui.Text("actions", "SetPermissionsForThePage",_node.Text); } override protected void OnInit(EventArgs e) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUser.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUser.aspx.cs index d9605506b4..9734401d95 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUser.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUser.aspx.cs @@ -30,6 +30,8 @@ using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; using PropertyType = umbraco.cms.businesslogic.propertytype.PropertyType; +using System.Text.RegularExpressions; +using System.Text; namespace umbraco.cms.presentation.user { @@ -43,11 +45,16 @@ namespace umbraco.cms.presentation.user CurrentApp = DefaultApps.users.ToString(); } protected HtmlTable macroProperties; - protected TextBox uname = new TextBox(); - protected TextBox lname = new TextBox(); + protected TextBox uname = new TextBox() { ID = "uname" }; + protected RequiredFieldValidator unameValidator = new RequiredFieldValidator(); + protected TextBox lname = new TextBox() { ID = "lname" }; + protected RequiredFieldValidator lnameValidator = new RequiredFieldValidator(); + protected CustomValidator lnameCustomValidator = new CustomValidator(); protected PlaceHolder passw = new PlaceHolder(); protected CheckBoxList lapps = new CheckBoxList(); - protected TextBox email = new TextBox(); + protected TextBox email = new TextBox() { ID = "email" }; + protected RequiredFieldValidator emailValidator = new RequiredFieldValidator(); + protected CustomValidator emailCustomValidator = new CustomValidator(); protected DropDownList userType = new DropDownList(); protected DropDownList userLanguage = new DropDownList(); protected CheckBox NoConsole = new CheckBox(); @@ -148,8 +155,7 @@ namespace umbraco.cms.presentation.user contentPicker.Value = "-1"; content.Controls.Add(contentPicker); - - + // Add password changer var passwordChanger = (passwordChanger)LoadControl(SystemDirectories.Umbraco + "/controls/passwordChanger.ascx"); passwordChanger.MembershipProviderName = UmbracoSettings.DefaultBackofficeProvider; @@ -173,10 +179,20 @@ namespace umbraco.cms.presentation.user passw.Controls.Add(passwordChanger); passw.Controls.Add(validatorContainer); - pp.addProperty(ui.Text("user", "username", UmbracoUser), uname); - pp.addProperty(ui.Text("user", "loginname", UmbracoUser), lname); + var validationSummary = new ValidationSummary + { + ID = "validationSummary", + DisplayMode = ValidationSummaryDisplayMode.BulletList, + CssClass = "error" + }; + + pp.addProperty(validationSummary); + + pp.addProperty(ui.Text("user", "username", UmbracoUser), uname, unameValidator); + pp.addProperty(ui.Text("user", "loginname", UmbracoUser), lname, lnameValidator, lnameCustomValidator); pp.addProperty(ui.Text("user", "password", UmbracoUser), passw); - pp.addProperty(ui.Text("email", UmbracoUser), email); + + pp.addProperty(ui.Text("general", "email", UmbracoUser), email, emailValidator, emailCustomValidator); pp.addProperty(ui.Text("user", "usertype", UmbracoUser), userType); pp.addProperty(ui.Text("user", "language", UmbracoUser), userLanguage); @@ -213,12 +229,56 @@ namespace umbraco.cms.presentation.user save.Text = ui.Text("save"); save.ButtonType = MenuButtonType.Primary; - sectionValidator.ServerValidate += new ServerValidateEventHandler(sectionValidator_ServerValidate); + sectionValidator.ServerValidate += SectionValidator_OnServerValidate; sectionValidator.ControlToValidate = lapps.ID; sectionValidator.ErrorMessage = ui.Text("errorHandling", "errorMandatoryWithoutTab", ui.Text("user", "modules", UmbracoUser), UmbracoUser); sectionValidator.CssClass = "error"; sectionValidator.Style.Add("color", "red"); + unameValidator.ControlToValidate = uname.ID; + unameValidator.Display = ValidatorDisplay.Dynamic; + unameValidator.ErrorMessage = ui.Text("defaultdialogs", "requiredField", UmbracoUser); + unameValidator.CssClass = "error"; + unameValidator.Style.Add("color", "red"); + unameValidator.Style.Add("margin-left", "5px"); + unameValidator.Style.Add("line-height", "28px"); + + lnameValidator.ControlToValidate = lname.ID; + lnameValidator.Display = ValidatorDisplay.Dynamic; + lnameValidator.ErrorMessage = ui.Text("defaultdialogs", "requiredField", UmbracoUser); + lnameValidator.CssClass = "error"; + lnameValidator.Style.Add("color", "red"); + lnameValidator.Style.Add("margin-left", "5px"); + lnameValidator.Style.Add("line-height", "28px"); + + lnameCustomValidator.ServerValidate += LnameCustomValidator_OnServerValidate; + lnameCustomValidator.Display = ValidatorDisplay.Dynamic; + lnameCustomValidator.ControlToValidate = lname.ID; + var localizedLname = ui.Text("user", "loginname", UmbracoUser); + lnameCustomValidator.ErrorMessage = ui.Text("errorHandling", "errorExistsWithoutTab", localizedLname, UmbracoUser); + lnameCustomValidator.CssClass = "error"; + lnameCustomValidator.Style.Add("color", "red"); + lnameCustomValidator.Style.Add("margin-left", "5px"); + lnameCustomValidator.Style.Add("line-height", "28px"); + + emailValidator.ControlToValidate = email.ID; + emailValidator.Display = ValidatorDisplay.Dynamic; + emailValidator.ErrorMessage = ui.Text("defaultdialogs", "requiredField", UmbracoUser); + emailValidator.CssClass = "error"; + emailValidator.Style.Add("color", "red"); + emailValidator.Style.Add("margin-left", "5px"); + emailValidator.Style.Add("line-height", "28px"); + + emailCustomValidator.ServerValidate += EmailCustomValidator_OnServerValidate; + emailCustomValidator.Display = ValidatorDisplay.Dynamic; + emailCustomValidator.ControlToValidate = email.ID; + var localizedEmail = ui.Text("general", "email", UmbracoUser); + emailCustomValidator.ErrorMessage = ui.Text("errorHandling", "errorRegExpWithoutTab", localizedEmail, UmbracoUser); + emailCustomValidator.CssClass = "error"; + emailCustomValidator.Style.Add("color", "red"); + emailCustomValidator.Style.Add("margin-left", "5px"); + emailCustomValidator.Style.Add("line-height", "28px"); + SetupForm(); SetupChannel(); @@ -227,8 +287,18 @@ namespace umbraco.cms.presentation.user .SyncTree(UID.ToString(), IsPostBack); } + private void LnameCustomValidator_OnServerValidate(object source, ServerValidateEventArgs args) + { + var usersWithLoginName = ApplicationContext.Services.UserService.GetByUsername(lname.Text); + args.IsValid = usersWithLoginName == null || usersWithLoginName.Id == u.Id; + } - void sectionValidator_ServerValidate(object source, ServerValidateEventArgs args) + private void EmailCustomValidator_OnServerValidate(object source, ServerValidateEventArgs args) + { + args.IsValid = MembershipProviderBase.IsEmailValid(email.Text.Trim()); + } + + private void SectionValidator_OnServerValidate(object source, ServerValidateEventArgs args) { args.IsValid = false; @@ -531,7 +601,9 @@ namespace umbraco.cms.presentation.user } else { - ClientTools.ShowSpeechBubble(speechBubbleIcon.error, ui.Text("speechBubbles", "editUserError", UmbracoUser), ""); + ClientTools.ShowSpeechBubble(speechBubbleIcon.error, + ui.Text("speechBubbles", "validationFailedHeader", UmbracoUser), + ui.Text("speechBubbles", "validationFailedMessage", UmbracoUser)); } } diff --git a/src/UmbracoExamine/UmbracoContentIndexer.cs b/src/UmbracoExamine/UmbracoContentIndexer.cs index f69e7e59bb..5acd5a077b 100644 --- a/src/UmbracoExamine/UmbracoContentIndexer.cs +++ b/src/UmbracoExamine/UmbracoContentIndexer.cs @@ -1,20 +1,12 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Linq; -using System.Security; -using System.Text; -using System.Web; using System.Xml.Linq; using Examine; -using Examine.Config; -using Examine.Providers; using Lucene.Net.Documents; -using Lucene.Net.Index; using Umbraco.Core; -using umbraco.cms.businesslogic; using Umbraco.Core.Models; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Services; @@ -22,12 +14,9 @@ using UmbracoExamine.DataServices; using Examine.LuceneEngine; using Examine.LuceneEngine.Config; using UmbracoExamine.Config; -using Examine.LuceneEngine.Providers; using Lucene.Net.Analysis; -using umbraco.BasePages; using Umbraco.Core.Persistence.Querying; using IContentService = Umbraco.Core.Services.IContentService; -using UmbracoExamine.LocalStorage; using IMediaService = Umbraco.Core.Services.IMediaService; @@ -42,6 +31,7 @@ namespace UmbracoExamine private readonly IMediaService _mediaService; private readonly IDataTypeService _dataTypeService; private readonly IUserService _userService; + private readonly IContentTypeService _contentTypeService; #region Constructors @@ -55,6 +45,7 @@ namespace UmbracoExamine _mediaService = ApplicationContext.Current.Services.MediaService; _dataTypeService = ApplicationContext.Current.Services.DataTypeService; _userService = ApplicationContext.Current.Services.UserService; + _contentTypeService = ApplicationContext.Current.Services.ContentTypeService; } /// @@ -73,6 +64,7 @@ namespace UmbracoExamine _mediaService = ApplicationContext.Current.Services.MediaService; _dataTypeService = ApplicationContext.Current.Services.DataTypeService; _userService = ApplicationContext.Current.Services.UserService; + _contentTypeService = ApplicationContext.Current.Services.ContentTypeService; } /// @@ -91,6 +83,7 @@ namespace UmbracoExamine _mediaService = ApplicationContext.Current.Services.MediaService; _dataTypeService = ApplicationContext.Current.Services.DataTypeService; _userService = ApplicationContext.Current.Services.UserService; + _contentTypeService = ApplicationContext.Current.Services.ContentTypeService; } /// @@ -105,6 +98,7 @@ namespace UmbracoExamine /// /// /// + [Obsolete("Use the overload that specifies the Umbraco services")] public UmbracoContentIndexer(IIndexCriteria indexerData, Lucene.Net.Store.Directory luceneDirectory, IDataService dataService, IContentService contentService, IMediaService mediaService, @@ -117,13 +111,43 @@ namespace UmbracoExamine _mediaService = mediaService; _dataTypeService = dataTypeService; _userService = userService; + _contentTypeService = ApplicationContext.Current.Services.ContentTypeService; + } + + /// + /// Constructor to allow for creating an indexer at runtime + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public UmbracoContentIndexer(IIndexCriteria indexerData, Lucene.Net.Store.Directory luceneDirectory, IDataService dataService, + IContentService contentService, + IMediaService mediaService, + IDataTypeService dataTypeService, + IUserService userService, + IContentTypeService contentTypeService, + Analyzer analyzer, bool async) + : base(indexerData, luceneDirectory, dataService, analyzer, async) + { + _contentService = contentService; + _mediaService = mediaService; + _dataTypeService = dataTypeService; + _userService = userService; + _contentTypeService = contentTypeService; } #endregion #region Constants & Fields - + /// /// Used to store the path of a content object @@ -206,13 +230,8 @@ namespace UmbracoExamine SupportProtectedContent = supportProtected; else SupportProtectedContent = false; - - + base.Initialize(name, config); - - - - } #endregion @@ -285,10 +304,7 @@ namespace UmbracoExamine #endregion #region Public methods - - - /// /// Overridden for logging /// @@ -308,7 +324,6 @@ namespace UmbracoExamine { DataService.LogService.AddErrorLog(-1, string.Format("ReIndexNode cannot proceed, the format of the XElement is invalid, the xml has no 'id' attribute. {0}", node)); } - } /// @@ -360,8 +375,6 @@ namespace UmbracoExamine switch (type) { case IndexTypes.Content: - - var contentParentId = -1; if (IndexerData.ParentNodeId.HasValue && IndexerData.ParentNodeId.Value > 0) { @@ -394,69 +407,62 @@ namespace UmbracoExamine { content = descendants.ToArray(); } - AddNodesToIndex(GetSerializedContent(content), type); pageIndex++; - - } while (content.Length == pageSize); break; case IndexTypes.Media: - var mediaParentId = -1; + if (IndexerData.ParentNodeId.HasValue && IndexerData.ParentNodeId.Value > 0) { mediaParentId = IndexerData.ParentNodeId.Value; } - IMedia[] media; + XElement[] mediaXElements; + + var mediaTypes = _contentTypeService.GetAllMediaTypes().ToArray(); + var icons = mediaTypes.ToDictionary(x => x.Id, y => y.Icon); + do { long total; - var descendants = _mediaService.GetPagedDescendants(mediaParentId, pageIndex, pageSize, out total); + if (mediaParentId == -1) + { + mediaXElements = _mediaService.GetPagedXmlEntries("-1", pageIndex, pageSize, out total).ToArray(); + } + else + { + //Get the parent + var parent = _mediaService.GetById(mediaParentId); + if (parent == null) + mediaXElements = new XElement[0]; + else + mediaXElements = _mediaService.GetPagedXmlEntries(parent.Path, pageIndex, pageSize, out total).ToArray(); + } //if specific types are declared we need to post filter them //TODO: Update the service layer to join the cmsContentType table so we can query by content type too if (IndexerData.IncludeNodeTypes.Any()) { - media = descendants.Where(x => IndexerData.IncludeNodeTypes.Contains(x.ContentType.Alias)).ToArray(); - } - else - { - media = descendants.ToArray(); + var includeNodeTypeIds = mediaTypes.Where(x => IndexerData.IncludeNodeTypes.Contains(x.Alias)).Select(x => x.Id); + mediaXElements = mediaXElements.Where(elm => includeNodeTypeIds.Contains(elm.AttributeValue("nodeType"))).ToArray(); } - AddNodesToIndex(GetSerializedMedia(media), type); + foreach (var element in mediaXElements) + { + element.Add(new XAttribute("icon", icons[element.AttributeValue("nodeType")])); + } + + AddNodesToIndex(mediaXElements, type); pageIndex++; - } while (media.Length == pageSize); + } while (mediaXElements.Length == pageSize); break; } } - private IEnumerable GetSerializedMedia(IEnumerable media) - { - var serializer = new EntityXmlSerializer(); - foreach (var m in media) - { - var xml = serializer.Serialize( - _mediaService, - _dataTypeService, - _userService, - m); - - //add a custom 'icon' attribute - if (m.ContentType.Icon.IsNullOrWhiteSpace() == false) - { - xml.Add(new XAttribute("icon", m.ContentType.Icon)); - } - - - yield return xml; - } - } - private IEnumerable GetSerializedContent(IEnumerable content) { var serializer = new EntityXmlSerializer(); @@ -513,7 +519,6 @@ namespace UmbracoExamine protected override void OnGatheringNodeData(IndexingNodeDataEventArgs e) { - //strip html of all users fields if we detect it has HTML in it. //if that is the case, we'll create a duplicate 'raw' copy of it so that we can return //the value of the field 'as-is'. @@ -549,7 +554,6 @@ namespace UmbracoExamine var icon = (string)e.Node.Attribute("icon"); if (!e.Fields.ContainsKey(IconFieldName)) e.Fields.Add(IconFieldName, icon); - } /// @@ -587,7 +591,6 @@ namespace UmbracoExamine } return fields; - } /// @@ -608,7 +611,6 @@ namespace UmbracoExamine { return base.GetIndexerData(indexSet); } - } /// @@ -638,10 +640,9 @@ namespace UmbracoExamine { return false; } - return base.ValidateDocument(node); } #endregion } -} +} \ No newline at end of file diff --git a/src/umbraco.cms/businesslogic/Packager/Installer.cs b/src/umbraco.cms/businesslogic/Packager/Installer.cs index bc1c062631..1f17da3922 100644 --- a/src/umbraco.cms/businesslogic/Packager/Installer.cs +++ b/src/umbraco.cms/businesslogic/Packager/Installer.cs @@ -396,7 +396,7 @@ namespace umbraco.cms.businesslogic.packager if (languageItemsElement != null) { var insertedLanguages = packagingService.ImportLanguages(languageItemsElement); - insPack.Data.Languages.AddRange(insertedLanguages.Select(l => l.Id.ToString())); + insPack.Data.Languages.AddRange(insertedLanguages.Select(l => l.Id.ToString(CultureInfo.InvariantCulture))); } #endregion @@ -406,24 +406,17 @@ namespace umbraco.cms.businesslogic.packager if (dictionaryItemsElement != null) { var insertedDictionaryItems = packagingService.ImportDictionaryItems(dictionaryItemsElement); - insPack.Data.DictionaryItems.AddRange(insertedDictionaryItems.Select(d => d.Id.ToString())); + insPack.Data.DictionaryItems.AddRange(insertedDictionaryItems.Select(d => d.Id.ToString(CultureInfo.InvariantCulture))); } #endregion #region Macros - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//macro")) + var macroItemsElement = rootElement.Descendants("Macros").FirstOrDefault(); + if (macroItemsElement != null) { - //TODO: Fix this, this should not use the legacy API - Macro m = Macro.Import(n); - - if (m != null) - { - insPack.Data.Macros.Add(m.Id.ToString(CultureInfo.InvariantCulture)); - //saveNeeded = true; - } + var insertedMacros = packagingService.ImportMacros(macroItemsElement); + insPack.Data.Macros.AddRange(insertedMacros.Select(m => m.Id.ToString(CultureInfo.InvariantCulture))); } - - //if (saveNeeded) { insPack.Save(); saveNeeded = false; } #endregion #region Templates @@ -461,7 +454,7 @@ namespace umbraco.cms.businesslogic.packager { StyleSheet s = StyleSheet.Import(n, currentUser); - insPack.Data.Stylesheets.Add(s.Id.ToString()); + insPack.Data.Stylesheets.Add(s.Id.ToString(CultureInfo.InvariantCulture)); //saveNeeded = true; } diff --git a/src/umbraco.cms/businesslogic/macro/Macro.cs b/src/umbraco.cms/businesslogic/macro/Macro.cs index 4ff30c404f..4031f54150 100644 --- a/src/umbraco.cms/businesslogic/macro/Macro.cs +++ b/src/umbraco.cms/businesslogic/macro/Macro.cs @@ -1,11 +1,8 @@ using System; -using System.Data; -using System.Globalization; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Xml; -using System.Runtime.CompilerServices; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.IO; @@ -185,23 +182,26 @@ namespace umbraco.cms.businesslogic.macro }).ToArray(); } } - - /// - /// Macro initializer - /// - public Macro() + + /// + /// Macro initializer + /// + [Obsolete("This should no longer be used, use the IMacroService and related models instead")] + public Macro() { } - /// - /// Macro initializer - /// - /// The id of the macro - public Macro(int Id) + /// + /// Macro initializer + /// + /// The id of the macro + [Obsolete("This should no longer be used, use the IMacroService and related models instead")] + public Macro(int Id) { Setup(Id); } + [Obsolete("This should no longer be used, use the IMacroService and related models instead")] internal Macro(IMacro macro) { MacroEntity = macro; @@ -211,15 +211,17 @@ namespace umbraco.cms.businesslogic.macro /// Initializes a new instance of the class. /// /// The alias. + [Obsolete("This should no longer be used, use the IMacroService and related models instead")] public Macro(string alias) { Setup(alias); } - /// - /// Used to persist object changes to the database. In Version3.0 it's just a stub for future compatibility - /// - public virtual void Save() + /// + /// Used to persist object changes to the database. In Version3.0 it's just a stub for future compatibility + /// + [Obsolete("This should no longer be used, use the IMacroService and related models instead")] + public virtual void Save() { //event var e = new SaveEventArgs(); @@ -250,8 +252,7 @@ namespace umbraco.cms.businesslogic.macro } } - //TODO: Fix this, this should wrap a new API! - + [Obsolete("This is no longer used, use the IMacroService and related models instead")] public static Macro Import(XmlNode n) { var alias = XmlHelper.GetNodeValue(n.SelectSingleNode("alias")); diff --git a/src/umbraco.controls/pane.cs b/src/umbraco.controls/pane.cs index 0facc946a3..499695debf 100644 --- a/src/umbraco.controls/pane.cs +++ b/src/umbraco.controls/pane.cs @@ -36,6 +36,22 @@ namespace umbraco.uicontrols set { m_title = value; } } + public void addProperty(string Caption, Control C, params BaseValidator[] validators) + { + + PropertyPanel pp = new PropertyPanel(); + pp.Controls.Add(C); + + foreach (var validator in validators) + { + validator.Display = ValidatorDisplay.Dynamic; + pp.Controls.Add(validator); + } + pp.Text = Caption; + + this.Controls.Add(pp); + } + public void addProperty(string Caption, Control C) {