Merge branch origin/temp8 into temp8-di2690

This commit is contained in:
Stephan
2018-12-21 10:58:38 +01:00
126 changed files with 1327 additions and 978 deletions
+2 -2
View File
@@ -47,7 +47,7 @@ namespace Umbraco.Core.Composing
/// <param name="runtimeCache">The application runtime cache.</param>
/// <param name="localTempStorage">Files storage mode.</param>
/// <param name="logger">A profiling logger.</param>
public TypeLoader(IRuntimeCacheProvider runtimeCache, LocalTempStorage localTempStorage, ProfilingLogger logger)
public TypeLoader(IRuntimeCacheProvider runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger)
: this(runtimeCache, localTempStorage, logger, true)
{ }
@@ -58,7 +58,7 @@ namespace Umbraco.Core.Composing
/// <param name="localTempStorage">Files storage mode.</param>
/// <param name="logger">A profiling logger.</param>
/// <param name="detectChanges">Whether to detect changes using hashes.</param>
internal TypeLoader(IRuntimeCacheProvider runtimeCache, LocalTempStorage localTempStorage, ProfilingLogger logger, bool detectChanges)
internal TypeLoader(IRuntimeCacheProvider runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger, bool detectChanges)
{
_runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache));
_localTempStorage = localTempStorage == LocalTempStorage.Unknown ? LocalTempStorage.Default : localTempStorage;
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class ContentElement : UmbracoConfigurationElement, IContentSection
{
private const string DefaultPreviewBadge = @"<a id=""umbracoPreviewBadge"" style=""z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;"" href=""#"" OnClick=""javascript:window.top.location.href = '{0}/endPreview.aspx?redir={1}'""><span style=""display:none;"">In Preview Mode - click to end</span></a>";
private const string DefaultPreviewBadge = @"<a id=""umbracoPreviewBadge"" style=""z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;"" href=""#"" OnClick=""javascript:window.top.location.href = '{0}/preview/end?redir={1}'""><span style=""display:none;"">In Preview Mode - click to end</span></a>";
[ConfigurationProperty("imaging")]
internal ContentImagingElement Imaging => (ContentImagingElement) this["imaging"];
-24
View File
@@ -1,24 +0,0 @@
namespace Umbraco.Core
{
public static partial class Constants
{
public static class Examine
{
/// <summary>
/// The alias of the internal member indexer
/// </summary>
public const string InternalMemberIndexer = "InternalMemberIndexer";
/// <summary>
/// The alias of the internal content indexer
/// </summary>
public const string InternalIndexer = "InternalIndexer";
/// <summary>
/// The alias of the external content indexer
/// </summary>
public const string ExternalIndexer = "ExternalIndexer";
}
}
}
+3 -3
View File
@@ -225,14 +225,14 @@ namespace Umbraco.Core
protected virtual bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger)
{
var umbracoPlan = new UmbracoPlan();
var stateValueKey = Upgrader.GetStateValueKey(umbracoPlan);
var upgrader = new UmbracoUpgrader();
var stateValueKey = upgrader.StateValueKey;
// no scope, no service - just directly accessing the database
using (var database = databaseFactory.CreateDatabase())
{
CurrentMigrationState = KeyValueService.GetValue(database, stateValueKey);
FinalMigrationState = umbracoPlan.FinalState;
FinalMigrationState = upgrader.Plan.FinalState;
}
logger.Debug<RuntimeState>("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", CurrentMigrationState, FinalMigrationState ?? "<null>");
@@ -7,6 +7,7 @@ namespace Umbraco.Core.Services
{
IEnumerable<IMemberGroup> GetAll();
IMemberGroup GetById(int id);
IEnumerable<IMemberGroup> GetByIds(IEnumerable<int> ids);
IMemberGroup GetByName(string name);
void Save(IMemberGroup memberGroup, bool raiseEvents = true);
void Delete(IMemberGroup memberGroup);
-10
View File
@@ -90,16 +90,6 @@ namespace Umbraco.Core.Services
string[] userGroups = null,
string filter = null);
/// <summary>
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method
/// </summary>
/// <remarks>
/// This method exists so that Umbraco developers can use one entry point to create/update users if they choose to.
/// </remarks>
/// <param name="user">The user to save the password for</param>
/// <param name="password">The password to save</param>
void SavePassword(IUser user, string password);
/// <summary>
/// Deletes or disables a User
/// </summary>
@@ -2708,11 +2708,6 @@ namespace Umbraco.Core.Services.Implement
{
scope.WriteLock(Constants.Locks.ContentTree);
if (string.IsNullOrWhiteSpace(content.Name))
{
throw new ArgumentException("Cannot save content blueprint with empty name.");
}
if (content.HasIdentity == false)
{
content.CreatorId = userId;
@@ -739,7 +739,7 @@ namespace Umbraco.Core.Services.Implement
try
{
var container = new EntityContainer(Constants.ObjectTypes.DocumentType)
var container = new EntityContainer(ContainedObjectType)
{
Name = name,
ParentId = parentId,
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
@@ -60,6 +61,19 @@ namespace Umbraco.Core.Services.Implement
}
}
public IEnumerable<IMemberGroup> GetByIds(IEnumerable<int> ids)
{
if (ids == null || ids.Any() == false)
{
return new IMemberGroup[0];
}
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
return _memberGroupRepository.GetMany(ids.ToArray());
}
}
public IMemberGroup GetById(int id)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
@@ -227,30 +227,6 @@ namespace Umbraco.Core.Services.Implement
Save(membershipUser);
}
[Obsolete("ASP.NET Identity APIs like the BackOfficeUserManager should be used to manage passwords, this will not work with correct security practices because you would need the existing password")]
[EditorBrowsable(EditorBrowsableState.Never)]
public void SavePassword(IUser user, string password)
{
if (user == null) throw new ArgumentNullException(nameof(user));
var provider = MembershipProviderExtensions.GetUsersMembershipProvider();
if (provider.IsUmbracoMembershipProvider() == false)
throw new NotSupportedException("When using a non-Umbraco membership provider you must change the user password by using the MembershipProvider.ChangePassword method");
provider.ChangePassword(user.Username, "", password);
//go re-fetch the member and update the properties that may have changed
var result = GetByUsername(user.Username);
if (result != null)
{
//should never be null but it could have been deleted by another thread.
user.RawPasswordValue = result.RawPasswordValue;
user.LastPasswordChangeDate = result.LastPasswordChangeDate;
user.UpdateDate = result.UpdateDate;
}
}
/// <summary>
/// Deletes or disables a User
/// </summary>
-1
View File
@@ -311,7 +311,6 @@
<Compile Include="Constants-DataTypes.cs" />
<Compile Include="Constants-Composing.cs" />
<Compile Include="Constants-DeploySelector.cs" />
<Compile Include="Constants-Examine.cs" />
<Compile Include="Constants-Icons.cs" />
<Compile Include="Constants-ObjectTypes.cs" />
<Compile Include="Constants-PackageRepository.cs" />
+26
View File
@@ -2,9 +2,12 @@
using System.Linq;
using Examine;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Version = Lucene.Net.Util.Version;
using Umbraco.Core.Logging;
namespace Umbraco.Examine
@@ -14,6 +17,29 @@ namespace Umbraco.Examine
/// </summary>
internal static class ExamineExtensions
{
public static bool TryParseLuceneQuery(string query)
{
//TODO: I'd assume there would be a more strict way to parse the query but not that i can find yet, for now we'll
// also do this rudimentary check
if (!query.Contains(":"))
return false;
try
{
//This will pass with a plain old string without any fields, need to figure out a way to have it properly parse
var parsed = new QueryParser(Version.LUCENE_30, "nodeName", new KeywordAnalyzer()).Parse(query);
return true;
}
catch (ParseException)
{
return false;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Forcibly unlocks all lucene based indexes
/// </summary>
@@ -167,7 +167,7 @@ namespace Umbraco.Tests.Benchmarks
[Benchmark]
public void EmitCtor()
{
var ctor = ReflectionUtilities.EmitConstuctor<Func<IFoo, Foo>>();
var ctor = ReflectionUtilities.EmitConstructor<Func<IFoo, Foo>>();
var foo = ctor(_foo);
}
@@ -110,7 +110,6 @@ namespace Umbraco.Tests.Cache.PublishedCache
}
[TestCase("id")]
[TestCase("nodeId")]
[TestCase("__NodeId")]
public void DictionaryDocument_Id_Keys(string key)
{
@@ -127,7 +126,6 @@ namespace Umbraco.Tests.Cache.PublishedCache
}
[TestCase("nodeName")]
[TestCase("__nodeName")]
public void DictionaryDocument_NodeName_Keys(string key)
{
var dicDoc = GetDictionaryDocument(nodeNameKey: key);
@@ -59,18 +59,17 @@ namespace Umbraco.Tests.Composing
// cleanup
var assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory;
foreach (var d in Directory.GetDirectories(Path.Combine(assDir.FullName, "TypeLoader")))
Directory.Delete(d, true);
var tlDir = Path.Combine(assDir.FullName, "TypeLoader");
if (!Directory.Exists(tlDir))
return;
Directory.Delete(tlDir, true);
}
private DirectoryInfo PrepareFolder()
{
var assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory;
var dir = Directory.CreateDirectory(Path.Combine(assDir.FullName, "TypeLoader", Guid.NewGuid().ToString("N")));
foreach (var f in dir.GetFiles())
{
f.Delete();
}
var tlDir = Path.Combine(assDir.FullName, "TypeLoader");
var dir = Directory.CreateDirectory(Path.Combine(tlDir, Guid.NewGuid().ToString("N")));
return dir;
}
@@ -53,8 +53,7 @@ namespace Umbraco.Tests.Configurations
SystemDirectories.Root = rootPath;
Assert.AreEqual(outcome, Current.Config.Global().GetUmbracoMvcArea());
}
[TestCase("/umbraco/umbraco.aspx")]
[TestCase("/umbraco/editContent.aspx")]
[TestCase("/install/default.aspx")]
[TestCase("/install/")]
@@ -143,7 +143,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
[Test]
public void PreviewBadge()
{
Assert.AreEqual(SettingsSection.Content.PreviewBadge, @"<a id=""umbracoPreviewBadge"" style=""z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;"" href=""#"" OnClick=""javascript:window.top.location.href = '{0}/endPreview.aspx?redir={1}'""><span style=""display:none;"">In Preview Mode - click to end</span></a>");
Assert.AreEqual(SettingsSection.Content.PreviewBadge, @"<a id=""umbracoPreviewBadge"" style=""z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;"" href=""#"" OnClick=""javascript:window.top.location.href = '{0}/preview/end?redir={1}'""><span style=""display:none;"">In Preview Mode - click to end</span></a>");
}
[Test]
public void ResolveUrlsFromTextString()
@@ -77,7 +77,7 @@
<PreviewBadge>
<![CDATA[
<a id="umbracoPreviewBadge" style="z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/endPreview.aspx?redir={1}'"><span style="display:none;">In Preview Mode - click to end</span></a>
<a id="umbracoPreviewBadge" style="z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/preview/end?redir={1}'"><span style="display:none;">In Preview Mode - click to end</span></a>
]]></PreviewBadge>
<!-- How Umbraco should handle errors during macro execution. Can be one of the following values:
@@ -32,8 +32,7 @@ namespace Umbraco.Tests.CoreThings
[TestCase("http://www.domain.com/umbraco/test/test.js", "", true)]
[TestCase("http://www.domain.com/umbrac", "", false)]
[TestCase("http://www.domain.com/test", "", false)]
[TestCase("http://www.domain.com/test/umbraco", "", false)]
[TestCase("http://www.domain.com/test/umbraco.aspx", "", false)]
[TestCase("http://www.domain.com/test/umbraco", "", false)]
[TestCase("http://www.domain.com/Umbraco/restServices/blah", "", true)]
[TestCase("http://www.domain.com/Umbraco/Backoffice/blah", "", true)]
[TestCase("http://www.domain.com/Umbraco/anything", "", true)]
@@ -62,8 +61,7 @@ namespace Umbraco.Tests.CoreThings
[TestCase("http://www.domain.com/install/test/test.js", true)]
[TestCase("http://www.domain.com/instal", false)]
[TestCase("http://www.domain.com/umbraco", false)]
[TestCase("http://www.domain.com/umbraco/umbraco", false)]
[TestCase("http://www.domain.com/test/umbraco.aspx", false)]
[TestCase("http://www.domain.com/umbraco/umbraco", false)]
public void Is_Installer_Request(string input, bool expected)
{
var source = new Uri(input);
@@ -0,0 +1,136 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
using Umbraco.Web.Routing;
namespace Umbraco.Tests.Routing
{
[TestFixture]
public class GetContentUrlsTests : UrlRoutingTestBase
{
private IUmbracoSettingsSection _umbracoSettings;
public override void SetUp()
{
base.SetUp();
//generate new mock settings and assign so we can configure in individual tests
_umbracoSettings = SettingsForTests.GenerateMockUmbracoSettings();
SettingsForTests.ConfigureSettings(_umbracoSettings);
}
private ILocalizedTextService GetTextService()
{
var textService = Mock.Of<ILocalizedTextService>(
x => x.Localize("content/itemNotPublished",
It.IsAny<CultureInfo>(),
It.IsAny<IDictionary<string, string>>()) == "content/itemNotPublished");
return textService;
}
private ILocalizationService GetLangService(params string[] isoCodes)
{
var allLangs = isoCodes
.Select(CultureInfo.GetCultureInfo)
.Select(culture => new Language(culture.Name)
{
CultureName = culture.DisplayName,
IsDefault = true,
IsMandatory = true
}).ToArray();
var langService = Mock.Of<ILocalizationService>(x => x.GetAllLanguages() == allLangs);
return langService;
}
[Test]
public void Content_Not_Published()
{
var contentType = MockedContentTypes.CreateBasicContentType();
var content = MockedContent.CreateBasicContent(contentType);
content.Id = 1046; //fixme: we are using this ID only because it's built into the test XML published cache
content.Path = "-1,1046";
var umbContext = GetUmbracoContext("http://localhost:8000");
var publishedRouter = CreatePublishedRouter(Factory,
contentFinders: new ContentFinderCollection(new[] { new ContentFinderByUrl(Logger) }));
var urls = content.GetContentUrls(publishedRouter,
umbContext,
GetLangService("en-US", "fr-FR"), GetTextService(), ServiceContext.ContentService,
Logger).ToList();
Assert.AreEqual(1, urls.Count);
Assert.AreEqual("content/itemNotPublished", urls[0].Text);
Assert.IsFalse(urls[0].IsUrl);
}
[Test]
public void Invariant_Root_Content_Published_No_Domains()
{
var contentType = MockedContentTypes.CreateBasicContentType();
var content = MockedContent.CreateBasicContent(contentType);
content.Id = 1046; //fixme: we are using this ID only because it's built into the test XML published cache
content.Path = "-1,1046";
content.Published = true;
var umbContext = GetUmbracoContext("http://localhost:8000",
urlProviders: new []{ new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper()) });
var publishedRouter = CreatePublishedRouter(Factory,
contentFinders:new ContentFinderCollection(new[]{new ContentFinderByUrl(Logger) }));
var urls = content.GetContentUrls(publishedRouter,
umbContext,
GetLangService("en-US", "fr-FR"), GetTextService(), ServiceContext.ContentService,
Logger).ToList();
Assert.AreEqual(1, urls.Count);
Assert.AreEqual("/home/", urls[0].Text);
Assert.AreEqual("en-US", urls[0].Culture);
Assert.IsTrue(urls[0].IsUrl);
}
[Test]
public void Invariant_Child_Content_Published_No_Domains()
{
var contentType = MockedContentTypes.CreateBasicContentType();
var parent = MockedContent.CreateBasicContent(contentType);
parent.Id = 1046; //fixme: we are using this ID only because it's built into the test XML published cache
parent.Name = "home";
parent.Path = "-1,1046";
parent.Published = true;
var child = MockedContent.CreateBasicContent(contentType);
child.Name = "sub1";
child.Id = 1173; //fixme: we are using this ID only because it's built into the test XML published cache
child.Path = "-1,1046,1173";
child.Published = true;
var umbContext = GetUmbracoContext("http://localhost:8000",
urlProviders: new[] { new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper()) });
var publishedRouter = CreatePublishedRouter(Factory,
contentFinders: new ContentFinderCollection(new[] { new ContentFinderByUrl(Logger) }));
var urls = child.GetContentUrls(publishedRouter,
umbContext,
GetLangService("en-US", "fr-FR"), GetTextService(), ServiceContext.ContentService,
Logger).ToList();
Assert.AreEqual(1, urls.Count);
Assert.AreEqual("/home/sub1/", urls[0].Text);
Assert.AreEqual("en-US", urls[0].Culture);
Assert.IsTrue(urls[0].IsUrl);
}
//TODO: We need a lot of tests here, the above was just to get started with being able to unit test this method
// * variant URLs without domains assigned, what happens?
// * variant URLs with domains assigned, but also having more languages installed than there are domains/cultures assigned
// * variant URLs with an ancestor culture unpublished
// * invariant URLs with ancestors as variants
// * ... probably a lot more
}
}
@@ -77,8 +77,7 @@ namespace Umbraco.Tests.Routing
// do not test for /base here as it's handled before EnsureUmbracoRoutablePage is called
[TestCase("/umbraco_client/Tree/treeIcons.css", false)]
[TestCase("/umbraco_client/Tree/Themes/umbraco/style.css?cdv=37", false)]
[TestCase("/umbraco/umbraco.aspx", false)]
[TestCase("/umbraco_client/Tree/Themes/umbraco/style.css?cdv=37", false)]
[TestCase("/umbraco/editContent.aspx", false)]
[TestCase("/install/default.aspx", false)]
[TestCase("/install/?installStep=license", false)]
@@ -419,8 +419,8 @@ namespace Umbraco.Tests.Routing
foreach (var x in result) Console.WriteLine(x);
Assert.AreEqual(2, result.Length);
Assert.IsTrue(result.Contains("http://domain1a.com/en/1001-1-1/"));
Assert.IsTrue(result.Contains("http://domain1b.com/en/1001-1-1/"));
Assert.AreEqual(result[0].Text, "http://domain1b.com/en/1001-1-1/");
Assert.AreEqual(result[1].Text, "http://domain1a.com/en/1001-1-1/");
}
}
}
@@ -182,7 +182,7 @@ namespace Umbraco.Tests.Runtimes
pcontent = umbracoContext.ContentCache.GetById(true, content.Id);
Assert.IsNotNull(pcontent);
Assert.AreEqual("test", pcontent.Name);
Assert.IsTrue(pcontent.IsDraft);
Assert.IsTrue(pcontent.IsDraft());
// no published url
Assert.AreEqual("#", pcontent.GetUrl());
@@ -196,7 +196,7 @@ namespace Umbraco.Tests.Runtimes
pcontent = umbracoContext.ContentCache.GetById(content.Id);
Assert.IsNotNull(pcontent);
Assert.AreEqual("test", pcontent.Name);
Assert.IsFalse(pcontent.IsDraft);
Assert.IsFalse(pcontent.IsDraft());
// but the url is the published one - no draft url
Assert.AreEqual("/test/", pcontent.GetUrl());
@@ -205,7 +205,7 @@ namespace Umbraco.Tests.Runtimes
pcontent = umbracoContext.ContentCache.GetById(true, content.Id);
Assert.IsNotNull(pcontent);
Assert.AreEqual("testx", pcontent.Name);
Assert.IsTrue(pcontent.IsDraft);
Assert.IsTrue(pcontent.IsDraft());
// and the published document has a url
Assert.AreEqual("/test/", pcontent.GetUrl());
@@ -1,6 +1,6 @@
using System;
using System.Linq;
using LightInject;
using Umbraco.Core.Composing;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
@@ -36,7 +36,7 @@ namespace Umbraco.Tests.Services
base.Compose();
// fixme - do it differently
Container.Register(factory => factory.GetInstance<ServiceContext>().TextService);
Composition.Register(factory => factory.GetInstance<ServiceContext>().TextService);
}
[Test]
@@ -149,7 +149,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
var urlHelper = new Mock<IUrlProvider>();
urlHelper.Setup(provider => provider.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlProviderMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
.Returns("/hello/world/1234");
.Returns(UrlInfo.Url("/hello/world/1234"));
var membershipHelper = new MembershipHelper(new TestUmbracoContextAccessor(umbCtx), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), null, Mock.Of<CacheHelper>(), Mock.Of<ILogger>());
@@ -77,7 +77,7 @@ namespace Umbraco.Tests.Testing.TestingTests
var urlProviderMock = new Mock<IUrlProvider>();
urlProviderMock.Setup(provider => provider.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlProviderMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
.Returns("/hello/world/1234");
.Returns(UrlInfo.Url("/hello/world/1234"));
var urlProvider = urlProviderMock.Object;
var theUrlProvider = new UrlProvider(umbracoContext, new [] { urlProvider }, umbracoContext.VariationContextAccessor);
+1
View File
@@ -135,6 +135,7 @@
<Compile Include="PublishedContent\SolidPublishedSnapshot.cs" />
<Compile Include="PublishedContent\NuCacheTests.cs" />
<Compile Include="Runtimes\StandaloneTests.cs" />
<Compile Include="Routing\GetContentUrlsTests.cs" />
<Compile Include="Services\ContentServicePublishBranchTests.cs" />
<Compile Include="Services\ContentServiceTagsTests.cs" />
<Compile Include="Services\ContentTypeServiceVariantsTests.cs" />
@@ -79,7 +79,7 @@ namespace Umbraco.Tests.Web.Controllers
});
var textService = new Mock<ILocalizedTextService>();
textService.Setup(x => x.Localize(It.IsAny<string>(), It.IsAny<CultureInfo>(), It.IsAny<IDictionary<string, string>>())).Returns("");
textService.Setup(x => x.Localize(It.IsAny<string>(), It.IsAny<CultureInfo>(), It.IsAny<IDictionary<string, string>>())).Returns("text");
Composition.RegisterUnique(f => Mock.Of<IContentService>());
Composition.RegisterUnique(f => userServiceMock.Object);
@@ -78,7 +78,7 @@ namespace Umbraco.Tests.Web
var testUrlProvider = new Mock<IUrlProvider>();
testUrlProvider
.Setup(x => x.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlProviderMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
.Returns((UmbracoContext umbCtx, IPublishedContent content, UrlProviderMode mode, string culture, Uri url) => "/my-test-url");
.Returns((UmbracoContext umbCtx, IPublishedContent content, UrlProviderMode mode, string culture, Uri url) => UrlInfo.Url("/my-test-url"));
var globalSettings = SettingsForTests.GenerateMockGlobalSettings();
@@ -24,16 +24,19 @@
$scope.page.hideActionsMenu = infiniteMode ? true : false;
$scope.page.hideChangeVariant = infiniteMode ? true : false;
$scope.allowOpen = true;
$scope.app = null;
function init(content) {
// set first app to active
content.apps[0].active = true;
if (!$scope.app) {
// set first app to active
content.apps[0].active = true;
$scope.app = content.apps[0];
}
if (infiniteMode) {
createInfiniteModeButtons(content);
} else {
createButtons(content, content.apps[0]);
createButtons(content);
}
editorState.set($scope.content);
@@ -146,11 +149,11 @@
* @param {any} content the content node
* @param {any} app the active content app
*/
function createButtons(content, app) {
function createButtons(content) {
// only create the save/publish/preview buttons if the
// content app is "Conent"
if (app && app.alias !== "umbContent" && app.alias !== "umbInfo") {
if ($scope.app && $scope.app.alias !== "umbContent" && $scope.app.alias !== "umbInfo") {
$scope.defaultButton = null;
$scope.subButtons = null;
$scope.page.showSaveButton = false;
@@ -899,7 +902,8 @@
* @param {any} app
*/
$scope.appChanged = function (app) {
createButtons($scope.content, app);
$scope.app = app;
createButtons($scope.content);
};
// methods for infinite editing
@@ -10,6 +10,8 @@
var auditTrailLoaded = false;
var labels = {};
scope.publishStatus = [];
scope.currentVariant = null;
scope.currentUrls = [];
scope.disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates;
scope.allowChangeDocumentType = false;
@@ -17,18 +19,27 @@
function onInit() {
// set currentVariant
scope.currentVariant = _.find(scope.node.variants, (v) => v.active);
// find the urls for the currently selected language
if(scope.node.variants.length > 1) {
// nodes with variants
scope.currentUrls = _.filter(scope.node.urls, (url) => scope.currentVariant.language.culture === url.culture);
} else {
// invariant nodes
scope.currentUrls = scope.node.urls;
}
// if there are any infinite editors open we are in infinite editing
scope.isInfiniteMode = editorService.getNumberOfEditors() > 0 ? true : false;
userService.getCurrentUser().then(function(user){
// only allow change of media type if user has access to the settings sections
angular.forEach(user.sections, function(section){
if(section.alias === "settings" && !scope.isInfiniteMode) {
scope.allowChangeDocumentType = true;
scope.allowChangeTemplate = true;
}
});
});
// only allow change of media type if user has access to the settings sections
const hasAccessToSettings = user.allowedSections.indexOf("settings") !== -1 ? true : false;
scope.allowChangeDocumentType = hasAccessToSettings;
scope.allowChangeTemplate = hasAccessToSettings;
});
var keys = [
"general_deleted",
@@ -37,7 +48,10 @@
"content_publishedPendingChanges",
"content_notCreated",
"prompt_unsavedChanges",
"prompt_doctypeChangeWarning"
"prompt_doctypeChangeWarning",
"general_history",
"auditTrails_historyIncludingVariants",
"content_itemNotPublished"
];
localizationService.localizeMany(keys)
@@ -49,8 +63,22 @@
labels.notCreated = data[4];
labels.unsavedChanges = data[5];
labels.doctypeChangeWarning = data[6];
labels.notPublished = data[9];
scope.historyLabel = scope.node.variants && scope.node.variants.length === 1 ? data[7] : data[8];
setNodePublishStatus();
setNodePublishStatus(scope.node);
if (scope.currentUrls.length === 0) {
if (scope.node.id > 0) {
//it's created but not published
scope.currentUrls.push({ text: labels.notPublished, isUrl: false });
}
else {
//it's new
scope.currentUrls.push({ text: labels.notCreated, isUrl: false })
}
}
});
@@ -58,6 +86,9 @@
"id": scope.node.id
};
// make sure dates are formatted to the user's locale
formatDatesToLocal();
// get available templates
scope.availableTemplates = scope.node.allowedTemplates;
@@ -221,12 +252,13 @@
function setAuditTrailLogTypeColor(auditTrail) {
angular.forEach(auditTrail, function (item) {
switch (item.logType) {
case "Publish":
case "PublishVariant":
item.logTypeColor = "success";
break;
case "Unpublish":
case "UnpublishVariant":
case "Delete":
item.logTypeColor = "danger";
break;
@@ -236,51 +268,40 @@
});
}
function setNodePublishStatus(node) {
function setNodePublishStatus() {
scope.publishStatus = [];
scope.status = {};
// deleted node
if (node.trashed === true) {
scope.publishStatus.push({
label: labels.deleted,
color: "danger"
});
if (scope.node.trashed === true) {
scope.status.color = "danger";
return;
}
if (node.variants) {
for (var i = 0; i < node.variants.length; i++) {
var variant = node.variants[i];
var status = {
culture: variant.language ? variant.language.culture : null
};
if (variant.state === "NotCreated") {
status.label = labels.notCreated;
status.color = "gray";
}
else if (variant.state === "Draft") {
// draft node
status.label = labels.unpublished;
status.color = "gray";
}
else if (variant.state === "Published") {
// published node
status.label = labels.published;
status.color = "success";
}
else if (variant.state === "PublishedPendingChanges") {
// published node with pending changes
status.label = labels.publishedPendingChanges;
status.color = "success";
}
scope.publishStatus.push(status);
}
// variant status
if (scope.currentVariant.state === "NotCreated") {
// not created
scope.status.color = "gray";
}
else if (scope.currentVariant.state === "Draft") {
// draft node
scope.status.color = "gray";
}
else if (scope.currentVariant.state === "Published") {
// published node
scope.status.color = "success";
}
else if (scope.currentVariant.state === "PublishedPendingChanges") {
// published node with pending changes
scope.status.color = "success";
}
}
function formatDatesToLocal() {
// get current backoffice user and format dates
userService.getCurrentUser().then(function (currentUser) {
scope.currentVariant.createDateFormatted = dateHelper.getLocalDate(scope.currentVariant.createDate, currentUser.locale, 'LLL');
});
}
// load audit trail and redirects when on the info tab
@@ -306,7 +327,7 @@
auditTrailLoaded = false;
loadAuditTrail();
loadRedirectUrls();
setNodePublishStatus(scope.node);
setNodePublishStatus();
}
});
@@ -25,25 +25,6 @@
// shown so we don't animate a lot of editors which aren't necessary
var moveEditors = editorsElement.querySelectorAll('.umb-editor:nth-last-child(-n+'+ allowedNumberOfVisibleEditors +')');
// this is a temporary fix because the animations doesn't perform well
// TODO: fix animation and remove this
moveEditors.forEach(function(editor, index){
// resize the small editors to 100% so we can easily slide them
if(editor.classList.contains("umb-editor--small")) {
editor.style.width = "100%";
}
// set left position to indent the editors
if(scope.editors.length >= allowedNumberOfVisibleEditors) {
$(editor).css({"left": index * editorIndent});
} else {
$(editor).css({"left": (index + 1) * editorIndent});
}
});
/*
// collapse open editors before opening the new one
var collapseEditorAnimation = anime({
targets: moveEditors,
@@ -61,9 +42,8 @@
return (index + 1) * editorIndent;
},
easing: 'easeInOutQuint',
duration: 500
duration: 300
});
*/
// push the new editor to the dom
scope.editors.push(editor);
@@ -95,7 +75,7 @@
translateX: [100 + '%', 0],
opacity: [0, 1],
easing: 'easeInOutQuint',
duration: 400,
duration: 300,
complete: function() {
$timeout(function(){
editor.animating = false;
@@ -126,11 +106,12 @@
$timeout(function(){
scope.editors.splice(-1,1);
removeOverlayFromPrevEditor();
expandEditors();
});
}
});
expandEditors();
});
}
@@ -142,42 +123,32 @@
var editorsElement = el[0];
// only select the editors which are allowed to be
// shown so we don't animate a lot of editors which aren't necessary
var moveEditors = editorsElement.querySelectorAll('.umb-editor:nth-last-child(-n+'+ 4 +')');
// as the last element hasn't been removed from the dom yet we have to select the last four and then skip the last child (as it is the one closing).
var moveEditors = editorsElement.querySelectorAll('.umb-editor:nth-last-child(-n+'+ allowedNumberOfVisibleEditors + 1 +'):not(:last-child)');
var editorWidth = editorsElement.offsetWidth;
// this is a temporary fix because the animations doesn't perform well
// TODO: fix animation and remove this
moveEditors.forEach(function(editor, index){
// set left position
$(editor).css({"left": (index + 1) * editorIndent});
// if the new top editor is a small editor we will have to resize it back to the right size on
// move it all the way to the right side
if(editor.classList.contains("umb-editor--small") && index + 1 === moveEditors.length) {
editor.style.width = "500px";
$(editor).css({"left": ""});
}
});
// We need to figure out how to performance optimize this
// TODO: optimize animation
/*
var expandEditorAnimation = anime({
targets: moveEditors,
left: function(el, index, length){
return (index + 1) * editorIndent;
// move the editor all the way to the right if the top one is a small
if(el.classList.contains("umb-editor--small")) {
// only change the size if it is the editor on top
if(index + 1 === length) {
return editorWidth - 500;
}
} else {
return (index + 1) * editorIndent;
}
},
width: function(el, index, length) {
if(el.classList.contains("umb-editor--small")) {
// set the correct size if the top editor is of type "small"
if(el.classList.contains("umb-editor--small") && index + 1 === length) {
return "500px";
}
},
easing: 'easeInOutQuint',
duration: 500,
completed: function() {
}
duration: 300
});
*/
});
@@ -278,7 +278,7 @@ function umbTreeDirective($q, $rootScope, treeService, notificationsService, use
if (forceReload || (node.hasChildren && node.children.length === 0)) {
//get the children from the tree service
return treeService.loadNodeChildren({ node: node, section: $scope.section })
return treeService.loadNodeChildren({ node: node, section: $scope.section, isDialog: $scope.isdialog })
.then(function(data) {
//emit expanded event
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: node, children: data });
@@ -29,11 +29,11 @@ angular.module("umbraco.directives")
currentNode: '=',
enablelistviewexpand: '@',
node: '=',
tree: '='
tree: '=',
isDialog: '='
},
link: function (scope, element, attrs, umbTreeCtrl) {
localizationService.localize("general_search").then(function (value) {
scope.searchAltText = value;
});
@@ -18,7 +18,7 @@ angular.module('umbraco.mocks').
"actions_createPackage": "Create Package",
"actions_delete": "Delete",
"actions_disable": "Disable",
"actions_emptyTrashcan": "Empty recycle bin",
"actions_emptyRecycleBin": "Empty recycle bin",
"actions_exportDocumentType": "Export Document Type",
"actions_importDocumentType": "Import Document Type",
"actions_importPackage": "Import Package",
@@ -170,7 +170,6 @@ angular.module('umbraco.mocks').
"defaultdialogs_closeThisWindow": "Close this window",
"defaultdialogs_confirmdelete": "Are you sure you want to delete",
"defaultdialogs_confirmdisable": "Are you sure you want to disable",
"defaultdialogs_confirmEmptyTrashcan": "Please check this box to confirm deletion of %0% item(s)",
"defaultdialogs_confirmlogout": "Are you sure?",
"defaultdialogs_confirmSure": "Are you sure?",
"defaultdialogs_cut": "Cut",
@@ -29,6 +29,22 @@ function memberGroupResource($q, $http, umbRequestHelper) {
"Failed to retrieve member group");
},
getByIds: function (ids) {
var idQuery = "";
_.each(ids, function (item) {
idQuery += "ids=" + item + "&";
});
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"memberGroupApiBaseUrl",
"GetByIds",
idQuery)),
"Failed to retrieve member group");
},
deleteById: function (id) {
return umbRequestHelper.resourcePromise(
@@ -5,29 +5,29 @@
* @description
* Added in Umbraco 8.0. Application-wide service for handling infinite editing.
*
*
*
*
<h2><strong>Open a build-in infinite editor (media picker)</strong></h2>
<h3>Markup example</h3>
<pre>
<div ng-controller="My.Controller as vm">
<button type="button" ng-click="vm.open()">Open</button>
<div ng-controller="My.MediaPickerController as vm">
<button type="button" ng-click="vm.openMediaPicker()">Open</button>
</div>
</pre>
<h3>Controller example</h3>
<pre>
(function () {
"use strict";
function Controller() {
function MediaPickerController(editorService) {
var vm = this;
vm.open = open;
vm.openMediaPicker = openMediaPicker;
function open() {
function openMediaPicker() {
var mediaPickerOptions = {
multiPicker: true,
submit: function(model) {
@@ -36,22 +36,29 @@
close: function() {
editorService.close();
}
}
};
editorService.mediaPicker(mediaPickerOptions);
};
}
angular.module("umbraco").controller("My.Controller", Controller);
angular.module("umbraco").controller("My.MediaPickerController", MediaPickerController);
})();
</pre>
<h3>Custom view example</h3>
<h2><strong>Building a custom infinite editor</strong></h2>
<h3>Open the custom infinite editor (Markup)</h3>
<pre>
<div ng-controller="My.Controller as vm">
<button type="button" ng-click="vm.open()">Open</button>
</div>
</pre>
<h3>Open the custom infinite editor (Controller)</h3>
<pre>
(function () {
"use strict";
function Controller() {
function Controller(editorService) {
var vm = this;
@@ -59,14 +66,15 @@
function open() {
var options = {
view: "path/to/view.html"
title: "My custom infinite editor",
view: "path/to/view.html",
submit: function(model) {
editorService.close();
},
close: function() {
editorService.close();
}
}
};
editorService.open(options);
};
}
@@ -74,12 +82,89 @@
angular.module("umbraco").controller("My.Controller", Controller);
})();
</pre>
<h3><strong>The custom infinite editor view</strong></h3>
When building a custom infinite editor view you can use the same components as a normal editor ({@link umbraco.directives.directive:umbEditorView umbEditorView}).
<pre>
<div ng-controller="My.InfiniteEditorController as vm">
<umb-editor-view>
<umb-editor-header
name="model.title"
name-locked="true"
hide-alias="true"
hide-icon="true"
hide-description="true">
</umb-editor-header>
<umb-editor-container>
<umb-box>
<umb-box-content>
{{model | json}}
</umb-box-content>
</umb-box>
</umb-editor-container>
<umb-editor-footer>
<umb-editor-footer-content-right>
<umb-button
type="button"
button-style="link"
label-key="general_close"
action="vm.close()">
</umb-button>
<umb-button
type="button"
button-style="success"
label-key="general_submit"
action="vm.submit(model)">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>
</div>
</pre>
<h3>The custom infinite editor controller</h3>
<pre>
(function () {
"use strict";
function InfiniteEditorController($scope) {
var vm = this;
vm.submit = submit;
vm.close = close;
function submit() {
if($scope.model.submit) {
$scope.model.submit($scope.model);
}
}
function close() {
if($scope.model.close) {
$scope.model.close();
}
}
}
angular.module("umbraco").controller("My.InfiniteEditorController", InfiniteEditorController);
})();
</pre>
*/
(function () {
"use strict";
function editorService(eventsService) {
function editorService(eventsService, keyboardService) {
let editorsKeyboardShorcuts = [];
var editors = [];
/**
@@ -120,6 +205,12 @@
*/
function open(editor) {
/* keyboard shortcuts will be overwritten by the new infinite editor
so we need to store the shortcuts for the current editor so they can be rebound
when the infinite editor closes
*/
unbindKeyboardShortcuts();
// set flag so we know when the editor is open in "infinie mode"
editor.infiniteMode = true;
@@ -142,9 +233,9 @@
* Method to close the latest opened editor
*/
function close() {
var length = editors.length;
var closedEditor = editors[length - 1];
// close last opened editor
const closedEditor = editors[editors.length - 1];
editors.splice(-1, 1);
var args = {
@@ -152,7 +243,12 @@
editor: closedEditor
};
// emit event to let components know an editor has been removed
eventsService.emit("appState.editors.close", args);
// rebind keyboard shortcuts for the new editor in focus
rebindKeyboardShortcuts();
}
/**
@@ -652,6 +748,52 @@
open(editor);
}
///////////////////////
/**
* @ngdoc method
* @name umbraco.services.editorService#storeKeyboardShortcuts
* @methodOf umbraco.services.editorService
*
* @description
* Internal method to keep track of keyboard shortcuts registered
* to each editor so they can be rebound when an editor closes
*
*/
function unbindKeyboardShortcuts() {
const shortcuts = angular.copy(keyboardService.keyboardEvent);
editorsKeyboardShorcuts.push(shortcuts);
// unbind the current shortcuts because we only want to
// shortcuts from the newly opened editor working
for (let [key, value] of Object.entries(shortcuts)) {
keyboardService.unbind(key);
}
}
/**
* @ngdoc method
* @name umbraco.services.editorService#rebindKeyboardShortcuts
* @methodOf umbraco.services.editorService
*
* @description
* Internal method to rebind keyboard shortcuts for the editor in focus
*
*/
function rebindKeyboardShortcuts() {
// find the shortcuts from the previous editor
const lastSetOfShortcutsIndex = editorsKeyboardShorcuts.length - 1;
var lastSetOfShortcuts = editorsKeyboardShorcuts[lastSetOfShortcutsIndex];
// rebind shortcuts
for (let [key, value] of Object.entries(lastSetOfShortcuts)) {
keyboardService.bind(key, value.callback, value.opt);
}
// remove the shortcuts from the collection
editorsKeyboardShorcuts.splice(lastSetOfShortcutsIndex, 1);
}
var service = {
getEditors: getEditors,
getNumberOfEditors: getNumberOfEditors,
@@ -287,7 +287,10 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
throw "No node defined on args object for loadNodeChildren";
}
this.removeChildNodes(args.node);
// don't remove the children for container nodes in dialogs, as it'll remove the right arrow indicator
if (!args.isDialog || !args.node.metaData.isContainer) {
this.removeChildNodes(args.node);
}
args.node.loading = true;
return this.getChildren(args)
+32 -14
View File
@@ -47,7 +47,17 @@ app.run(['userService', '$q', '$log', '$rootScope', '$route', '$location', 'urlH
/** execute code on each successful route */
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
currentRouteParams = angular.copy(current.params); //store this so we can reference it in $routeUpdate
var toRetain = currentRouteParams ? navigationService.retainQueryStrings(currentRouteParams, current.params) : null;
//if toRetain is not null it means that there are missing query strings and we need to update the current params
if (toRetain) {
$route.updateParams(toRetain);
currentRouteParams = toRetain;
}
else {
currentRouteParams = angular.copy(current.params);
}
var deployConfig = Umbraco.Sys.ServerVariables.deploy;
var deployEnv, deployEnvTitle;
@@ -122,25 +132,33 @@ app.run(['userService', '$q', '$log', '$rootScope', '$route', '$location', 'urlH
$route.reload();
}
else {
var toRetain = navigationService.retainQueryStrings(currentRouteParams, next.params);
//if toRetain is not null it means that there are missing query strings and we need to update the current params
if (toRetain) {
$route.updateParams(toRetain);
}
//check if the location being changed is only due to global/state query strings which means the location change
//isn't actually going to cause a route change.
if (navigationService.isRouteChangingNavigation(currentRouteParams, next.params)) {
//The location change will cause a route change. We need to ensure that the global/state
//query strings have not been stripped out. If they have, we'll re-add them and re-route.
if (!toRetain && navigationService.isRouteChangingNavigation(currentRouteParams, next.params)) {
//The location change will cause a route change, continue the route if the query strings haven't been updated.
$route.reload();
var toRetain = navigationService.retainQueryStrings(currentRouteParams, next.params);
if (toRetain) {
$route.updateParams(toRetain);
}
else {
//continue the route
$route.reload();
}
}
else {
//navigation is not changing but we should update the currentRouteParams to include all current parameters
currentRouteParams = angular.copy(next.params);
if (toRetain) {
currentRouteParams = toRetain;
}
else {
currentRouteParams = angular.copy(next.params);
}
}
}
});
@@ -42,6 +42,6 @@
bottom: 0;
right: 0;
left: 0;
background: rgba(0,0,0,0.2);
background: rgba(0,0,0,0.4);
z-index: @zIndexEditor;
}
@@ -772,20 +772,6 @@
line-height: 1;
}
//
// Member group picker
// --------------------------------------------------
.umb-member-group-box {
width: 45%;
}
.umb-member-group-box:nth-child(1){
float:left;
}
.umb-member-group-box:nth-child(2){
float:right;
}
//
// Related links
// --------------------------------------------------
@@ -107,7 +107,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
/*****************************************************************************/
$scope.exitPreview = function () {
window.top.location.href = "../endPreview.aspx?redir=%2f" + $scope.pageId;
window.top.location.href = "../preview/end?redir=%2f" + $scope.pageId;
};
$scope.onFrameLoaded = function (iframe) {
@@ -17,7 +17,7 @@
vm.showValidationPattern = false;
vm.focusOnPatternField = false;
vm.focusOnMandatoryField = false;
vm.selectedValidationType = {};
vm.selectedValidationType = null;
vm.validationTypes = [];
vm.labels = {};
@@ -238,4 +238,4 @@
angular.module("umbraco").controller("Umbraco.Editors.PropertySettingsController", PropertySettingsEditor);
})();
})();
@@ -90,7 +90,7 @@
</label>
<select class="umb-dropdown" ng-options="validationType.name for validationType in vm.validationTypes" ng-model="vm.selectedValidationType" ng-change="vm.changeValidationType(vm.selectedValidationType)">
<option value=""><localize key="validation_validation">Validation</localize></option>
<option value=""><localize key="validation_noValidation">No validation</localize></option>
</select>
<textarea class="editor-validation-pattern"
@@ -2,21 +2,25 @@
<div class="umb-package-details__main-content">
<umb-box ng-if="node.urls" data-element="node-info-urls">
<umb-box ng-if="currentUrls" data-element="node-info-urls">
<umb-box-header title-key="general_links"></umb-box-header>
<umb-box-content class="block-form">
<ul class="nav nav-stacked" style="margin-bottom: 0;">
<li ng-repeat="url in node.urls">
<li ng-repeat="url in currentUrls">
<span ng-if="url.isUrl">
<span ng-if="node.variants.length === 1 && url.culture" style="font-size: 13px; color: #cccccc; width: 50px;display: inline-block">{{url.culture}}</span>
<a href="{{url.text}}" target="_blank">
<i class="icon icon-window-popin"></i>
<span>{{url.text}}</span>
</a>
<span ng-if="url.culture" style="font-size: 13px; color: #cccccc; margin-left: 20px;">{{url.culture}}</span>
</span>
<div ng-if="!url.isUrl" style="margin-top: 4px;">
<span>{{url.text}}</span>
<span ng-if="url.culture" style="font-size: 13px; color: #cccccc; margin-left: 20px;">{{url.culture}}</span>
<span ng-if="node.variants.length === 1 && url.culture" style="font-size: 13px; color: #cccccc; width: 50px;display: inline-block">{{url.culture}}</span>
<em>{{url.text}}</em>
</div>
</li>
</ul>
@@ -43,7 +47,8 @@
<umb-box data-element="node-info-history">
<umb-box-header
title-key="general_history">
title="{{historyLabel}}">
<umb-button
type="button"
button-style="outline"
@@ -62,8 +67,9 @@
<umb-load-indicator ng-show="loadingAuditTrail"></umb-load-indicator>
<div ng-show="auditTrail.length === 0" style="padding: 10px;">
<umb-empty-state position="center"
size="small">
<umb-empty-state
position="center"
size="small">
<localize key="content_noChanges"></localize>
</umb-empty-state>
</div>
@@ -96,7 +102,6 @@
class="history-item__badge"
size="xs"
color="{{item.logTypeColor}}">
<localize key="auditTrails_small{{ item.logType }}">{{ item.logType }}</localize>
</umb-badge>
<span>
@@ -130,16 +135,13 @@
<umb-box-content class="block-form">
<umb-control-group data-element="node-info-status" label="@general_status">
<div ng-repeat="status in publishStatus" style="margin-bottom: 5px;">
<span ng-show="status.culture"><em>{{status.culture}}: </em></span>
<umb-badge size="xs" color="{{status.color}}">
{{status.label}}
</umb-badge>
</div>
<umb-badge size="xs" color="{{status.color}}">
<umb-variant-state variant="currentVariant"></umb-variant-state>
</umb-badge>
</umb-control-group>
<umb-control-group ng-show="node.id !== 0" data-element="node-info-create-date" label="@template_createdDate">
{{node.createDateFormatted}} <localize key="general_by">by</localize> {{ node.owner.name }}
{{currentVariant.createDateFormatted}}
</umb-control-group>
<umb-control-group data-element="node-info-document-type" label="@content_documentType">
@@ -2,7 +2,7 @@
<div class="umb-tree-item__inner" ng-class="getNodeCssClass(node)" ng-swipe-right="options(node, $event)" ng-dblclick="load(node)" >
<ins data-element="tree-item-expand"
ng-class="{'icon-navigation-right': !node.expanded || node.metaData.isContainer, 'icon-navigation-down': node.expanded && !node.metaData.isContainer}"
ng-style="{'visibility': (node.hasChildren || node.metaData.isContainer && scope.enablelistviewexpand === 'true') ? 'visible' : 'hidden'}"
ng-style="{'visibility': (scope.enablelistviewexpand === 'true' || node.hasChildren && (!node.metaData.isContainer || isDialog)) ? 'visible' : 'hidden'}"
ng-click="load(node)">&nbsp;</ins>
<i class="icon umb-tree-icon sprTree" ng-class="::node.cssClass" title="{{::node.routePath}}" ng-click="select(node, $event)" ng-style="::node.style"></i>
@@ -14,7 +14,7 @@
</div>
<ul ng-class="{collapsed: !node.expanded}">
<umb-tree-item class="umb-animated" ng-repeat="child in node.children track by child.id" enablelistviewexpand="{{enablelistviewexpand}}" tree="tree" current-node="currentNode" node="child" section="{{section}}"></umb-tree-item>
<umb-tree-item class="umb-animated" ng-repeat="child in node.children track by child.id" enablelistviewexpand="{{enablelistviewexpand}}" tree="tree" current-node="currentNode" node="child" is-dialog="isDialog" section="{{section}}"></umb-tree-item>
</ul>
</li>
@@ -18,6 +18,7 @@
node="child"
current-node="currentNode"
tree="this"
is-dialog="isdialog"
section="{{section}}">
</umb-tree-item>
</li>
@@ -44,6 +45,7 @@
node="child"
current-node="currentNode"
tree="this"
is-dialog="isdialog"
section="{{section}}">
</umb-tree-item>
</li>
@@ -63,10 +63,10 @@
<div class="umb-table-row"
ng-repeat="child in miniListView.children"
ng-click="selectNode(child)"
ng-class="{'-selected':child.selected, 'not-allowed':!child.allowed}">
ng-class="{'umb-table-row--selected':child.selected, 'not-allowed':!child.allowed}">
<div class="umb-table-cell umb-table-cell--auto-width" ng-class="{'umb-table-cell--faded':child.published === false}">
<div class="flex items-center">
<ins class="icon-navigation-right umb-table__row-expand" ng-click="openNode($event, child)" ng-class="{'umb-table__row-expand--hidden': child.hasChildren !== true}">&nbsp;</ins>
<ins class="icon-navigation-right umb-table__row-expand" ng-click="openNode($event, child)" ng-class="{'umb-table__row-expand--hidden': child.metaData.hasChildren !== true}">&nbsp;</ins>
<i class="umb-table-body__icon umb-table-body__fileicon {{child.icon}}"></i>
<i class="umb-table-body__icon umb-table-body__checkicon icon-check"></i>
</div>
@@ -1,49 +1,58 @@
angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController",
function ($scope, relationResource, contentResource, navigationService, appState, treeService, localizationService) {
function ($scope, relationResource, contentResource, entityResource, navigationService, appState, treeService, localizationService) {
var node = $scope.currentNode;
$scope.source = _.clone($scope.currentNode);
$scope.error = null;
$scope.success = false;
$scope.success = false;
$scope.loading = true;
relationResource.getByChildId(node.id, "relateParentDocumentOnDelete").then(function (data) {
relationResource.getByChildId($scope.source.id, "relateParentDocumentOnDelete").then(function (data) {
$scope.loading = false;
if (data.length == 0) {
$scope.success = false;
$scope.error = {
errorMsg: localizationService.localize('recycleBin_itemCannotBeRestored'),
data: {
Message: localizationService.localize('recycleBin_noRestoreRelation')
}
}
if (!data.length) {
localizationService.localizeMany(["recycleBin_itemCannotBeRestored", "recycleBin_noRestoreRelation"])
.then(function(values) {
$scope.success = false;
$scope.error = {
errorMsg: values[0],
data: {
Message: values[1]
}
}
});
return;
}
$scope.relation = data[0];
if ($scope.relation.parentId == -1) {
if ($scope.relation.parentId === -1) {
$scope.target = { id: -1, name: "Root" };
} else {
contentResource.getById($scope.relation.parentId).then(function (data) {
} else {
$scope.loading = true;
entityResource.getById($scope.relation.parentId, "Document").then(function (data) {
$scope.loading = false;
$scope.target = data;
// make sure the target item isn't in the recycle bin
if($scope.target.path.indexOf("-20") !== -1) {
$scope.error = {
errorMsg: localizationService.localize('recycleBin_itemCannotBeRestored'),
data: {
Message: localizationService.localize('recycleBin_restoreUnderRecycled').then(function (value) {
value.replace('%0%', $scope.target.name);
})
}
};
localizationService.localizeMany(["recycleBin_itemCannotBeRestored", "recycleBin_restoreUnderRecycled"])
.then(function (values) {
$scope.success = false;
$scope.error = {
errorMsg: values[0],
data: {
Message: values[1].replace('%0%', $scope.target.name)
}
}
});
$scope.success = false;
}
}, function (err) {
$scope.success = false;
$scope.error = err;
$scope.loading = false;
});
}
@@ -53,10 +62,12 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController"
});
$scope.restore = function () {
$scope.loading = true;
// this code was copied from `content.move.controller.js`
contentResource.move({ parentId: $scope.target.id, id: node.id })
contentResource.move({ parentId: $scope.target.id, id: $scope.source.id })
.then(function (path) {
$scope.loading = false;
$scope.success = true;
//first we need to remove the node that launched the dialog
@@ -79,6 +90,12 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController"
}, function (err) {
$scope.success = false;
$scope.error = err;
$scope.loading = false;
});
};
};
$scope.close = function () {
navigationService.hideDialog();
};
});
@@ -2,25 +2,33 @@
<div class="umb-dialog-body">
<umb-pane>
<p class="abstract" ng-hide="error != null || success == true">
<localize key="actions_restore">Restore</localize> <strong>{{currentNode.name}}</strong> <localize key="general_under">under</localize> <strong>{{target.name}}</strong>?
<umb-load-indicator
ng-show="loading">
</umb-load-indicator>
<p class="abstract" ng-hide="loading || error != null || success">
<localize key="actions_restore">Restore</localize> <strong>{{source.name}}</strong> <localize key="general_under">under</localize> <strong>{{target.name}}</strong>?
</p>
<div class="alert alert-error" ng-show="error != null">
<div><strong>{{error.errorMsg}}</strong></div>
<div>{{error.data.Message}}</div>
</div>
<div ng-show="error">
<div class="alert alert-error">
<div><strong>{{error.errorMsg}}</strong></div>
<div>{{error.data.Message}}</div>
</div>
</div>
<div class="alert alert-success" ng-show="success == true">
<p><strong>{{currentNode.name}}</strong> <localize key="editdatatype_wasMoved">was moved underneath</localize> <strong>{{target.name}}</strong></p>
<button class="btn btn-primary" ng-click="nav.hideDialog()"><localize key="general_ok">OK</localize></button>
</div>
<div ng-show="success">
<div class="alert alert-success">
<strong>{{source.name}}</strong> <localize key="editdatatype_wasMoved">was moved underneath</localize> <strong>{{target.name}}</strong>
</div>
<button class="btn btn-primary" ng-click="close()"><localize key="general_ok">Ok</localize></button>
</div>
</umb-pane>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="success == true">
<a class="btn btn-link" ng-click="nav.hideDialog()"><localize key="general_cancel">Cancel</localize></a>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || success">
<a class="btn btn-link" ng-click="close()"><localize key="general_cancel">Cancel</localize></a>
<button class="btn btn-primary" ng-click="restore()" ng-show="error == null"><localize key="actions_restore">Restore</localize></button>
</div>
</div>
@@ -7,28 +7,47 @@
* The controller for the content editor
*/
function ContentBlueprintEditController($scope, $routeParams, contentResource) {
var excludedProps = ["_umb_urls", "_umb_releasedate", "_umb_expiredate", "_umb_template"];
function getScaffold() {
return contentResource.getScaffold(-1, $routeParams.doctype)
.then(function (scaffold) {
return initialize(scaffold);
});
}
function getScaffold() {
return contentResource.getScaffold(-1, $routeParams.doctype)
.then(function (scaffold) {
var lastTab = scaffold.tabs[scaffold.tabs.length - 1];
lastTab.properties = _.filter(lastTab.properties,
function(p) {
return excludedProps.indexOf(p.alias) === -1;
});
scaffold.allowPreview = false;
scaffold.allowedActions = ["A", "S", "C"];
function getBlueprintById(id) {
return contentResource.getBlueprintById(id).then(function (blueprint) {
return initialize(blueprint);
});
}
return scaffold;
});
}
function initialize(content) {
if (content.apps && content.apps.length) {
var contentApp = _.find(content.apps, function (app) {
return app.alias === "umbContent";
});
content.apps = [contentApp];
}
content.allowPreview = false;
content.allowedActions = ["A", "S", "C"];
return content;
}
$scope.contentId = $routeParams.id;
$scope.isNew = $routeParams.id === "-1";
$scope.saveMethod = contentResource.saveBlueprint;
$scope.getMethod = getBlueprintById;
$scope.getScaffoldMethod = getScaffold;
//load the default culture selected in the main tree if any
$scope.culture = $routeParams.cculture ? $routeParams.cculture : $routeParams.mculture;
//Bind to $routeUpdate which will execute anytime a location changes but the route is not triggered.
//This is so we can listen to changes on the cculture parameter since that will not cause a route change
// and then we can pass in the updated culture to the editor
$scope.$on('$routeUpdate', function (event, next) {
$scope.culture = next.params.cculture ? next.params.cculture : $routeParams.mculture;
});
$scope.contentId = $routeParams.id;
$scope.isNew = $routeParams.id === "-1";
$scope.saveMethod = contentResource.saveBlueprint;
$scope.getMethod = contentResource.getBlueprintById;
$scope.getScaffoldMethod = getScaffold;
}
angular.module("umbraco").controller("Umbraco.Editors.ContentBlueprint.EditController", ContentBlueprintEditController);
@@ -4,6 +4,7 @@
get-method="getMethod"
get-scaffold-method="getScaffoldMethod"
is-new="isNew"
tree-alias="contentblueprints">
tree-alias="contentblueprints"
culture="culture">
</content-editor>
</div>
@@ -1,62 +1,74 @@
angular.module("umbraco").controller("Umbraco.Editors.Media.RestoreController",
function ($scope, relationResource, mediaResource, navigationService, appState, treeService, localizationService) {
var node = $scope.currentNode;
$scope.source = _.clone($scope.currentNode);
$scope.error = null;
$scope.success = false;
$scope.loading = true;
relationResource.getByChildId(node.id, "relateParentDocumentOnDelete").then(function (data) {
relationResource.getByChildId($scope.source.id, "relateParentDocumentOnDelete").then(function (data) {
$scope.loading = false;
if (data.length == 0) {
$scope.success = false;
$scope.error = {
errorMsg: localizationService.localize('recycleBin_itemCannotBeRestored'),
data: {
Message: localizationService.localize('recycleBin_noRestoreRelation')
}
}
if (!data.length) {
localizationService.localizeMany(["recycleBin_itemCannotBeRestored", "recycleBin_noRestoreRelation"])
.then(function(values) {
$scope.success = false;
$scope.error = {
errorMsg: values[0],
data: {
Message: values[1]
}
}
});
return;
}
$scope.relation = data[0];
if ($scope.relation.parentId == -1) {
if ($scope.relation.parentId === -1) {
$scope.target = { id: -1, name: "Root" };
} else {
$scope.loading = true;
mediaResource.getById($scope.relation.parentId).then(function (data) {
$scope.loading = false;
$scope.target = data;
// make sure the target item isn't in the recycle bin
if ($scope.target.path.indexOf("-20") !== -1) {
$scope.error = {
errorMsg: localizationService.localize('recycleBin_itemCannotBeRestored'),
data: {
Message: localizationService.localize('recycleBin_restoreUnderRecycled').then(function (value) {
value.replace('%0%', $scope.target.name);
})
}
};
// make sure the target item isn't in the recycle bin
if ($scope.target.path.indexOf("-21") !== -1) {
localizationService.localizeMany(["recycleBin_itemCannotBeRestored", "recycleBin_restoreUnderRecycled"])
.then(function (values) {
$scope.success = false;
$scope.error = {
errorMsg: values[0],
data: {
Message: values[1].replace('%0%', $scope.target.name)
}
}
});
$scope.success = false;
}
}, function (err) {
$scope.success = false;
$scope.error = err;
$scope.loading = false;
});
}
}, function (err) {
$scope.success = false;
$scope.error = err;
$scope.loading = false;
});
$scope.restore = function () {
$scope.loading = true;
// this code was copied from `content.move.controller.js`
mediaResource.move({ parentId: $scope.target.id, id: node.id })
mediaResource.move({ parentId: $scope.target.id, id: $scope.source.id })
.then(function (path) {
$scope.loading = false;
$scope.success = true;
//first we need to remove the node that launched the dialog
@@ -79,6 +91,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.RestoreController",
}, function (err) {
$scope.success = false;
$scope.error = err;
$scope.loading = false;
});
};
@@ -2,24 +2,32 @@
<div class="umb-dialog-body">
<umb-pane>
<p class="abstract" ng-hide="error != null || success == true">
<localize key="actions_restore">Restore</localize> <strong>{{currentNode.name}}</strong> <localize key="general_under">under</localize> <strong>{{target.name}}</strong>?
<umb-load-indicator
ng-show="loading">
</umb-load-indicator>
<p class="abstract" ng-hide="loading || error != null || success">
<localize key="actions_restore">Restore</localize> <strong>{{source.name}}</strong> <localize key="general_under">under</localize> <strong>{{target.name}}</strong>?
</p>
<div class="alert alert-error" ng-show="error != null">
<div><strong>{{error.errorMsg}}</strong></div>
<div>{{error.data.Message}}</div>
</div>
<div ng-show="error">
<div class="alert alert-error">
<div><strong>{{error.errorMsg}}</strong></div>
<div>{{error.data.Message}}</div>
</div>
</div>
<div class="alert alert-success" ng-show="success == true">
<p><strong>{{currentNode.name}}</strong> <localize key="editdatatype_wasMoved">was moved underneath</localize> <strong>{{target.name}}</strong></p>
<button class="btn btn-primary" ng-click="nav.hideDialog()"><localize key="general_ok">OK</localize></button>
</div>
<div ng-show="success">
<div class="alert alert-success">
<strong>{{source.name}}</strong> <localize key="editdatatype_wasMoved">was moved underneath</localize> <strong>{{target.name}}</strong>
</div>
<button class="btn btn-primary" ng-click="close()"><localize key="general_ok">Ok</localize></button>
</div>
</umb-pane>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="success == true">
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || success">
<a class="btn btn-link" ng-click="close()"><localize key="general_cancel">Cancel</localize></a>
<button class="btn btn-primary" ng-click="restore()" ng-show="error == null"><localize key="actions_restore">Restore</localize></button>
</div>
@@ -1,6 +1,6 @@
//this controller simply tells the dialogs service to open a memberPicker window
//with a specified callback, this callback will receive an object with a selection on it
function memberGroupPicker($scope, editorService){
function memberGroupPicker($scope, editorService, memberGroupResource){
function trim(str, chr) {
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
@@ -9,26 +9,35 @@ function memberGroupPicker($scope, editorService){
$scope.renderModel = [];
$scope.allowRemove = true;
$scope.groupIds = [];
if ($scope.model.value) {
var modelIds = $scope.model.value.split(',');
_.each(modelIds, function (item, i) {
$scope.renderModel.push({ name: item, id: item, icon: 'icon-users' });
var groupIds = $scope.model.value.split(',');
memberGroupResource.getByIds(groupIds).then(function(groups) {
$scope.renderModel = groups;
});
}
$scope.openMemberGroupPicker = function() {
var memberGroupPicker = {
multiPicker: true,
submit: function(model) {
if(model.selectedMemberGroups) {
_.each(model.selectedMemberGroups, function (item, i) {
$scope.add(item);
submit: function (model) {
var selectedGroupIds = _.map(model.selectedMemberGroups
? model.selectedMemberGroups
: [model.selectedMemberGroup],
function (id) { return parseInt(id); }
);
// figure out which groups are new and fetch them
var newGroupIds = _.difference(selectedGroupIds, renderModelIds());
if (newGroupIds && newGroupIds.length) {
memberGroupResource.getByIds(newGroupIds).then(function (groups) {
$scope.renderModel = _.union($scope.renderModel, groups);
editorService.close();
});
}
if(model.selectedMemberGroup) {
$scope.clear();
$scope.add(model.selectedMemberGroup);
else {
// no new groups selected
editorService.close();
}
editorService.close();
},
@@ -57,11 +66,14 @@ function memberGroupPicker($scope, editorService){
$scope.renderModel = [];
};
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var currIds = _.map($scope.renderModel, function (i) {
function renderModelIds() {
return _.map($scope.renderModel, function (i) {
return i.id;
});
$scope.model.value = trim(currIds.join(), ",");
}
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
$scope.model.value = trim(renderModelIds().join(), ",");
});
//when the scope is destroyed we need to unsubscribe
@@ -2,7 +2,7 @@
<div ng-model="renderModel">
<umb-node-preview
ng-repeat="node in renderModel"
ng-repeat="node in renderModel | orderBy:'name'"
icon="node.icon"
name="node.name"
allow-remove="allowRemove"
@@ -1,15 +1,4 @@
function memberGroupController($scope) {
//set the available to the keys of the dictionary who's value is true
$scope.getAvailable = function () {
var available = [];
for (var n in $scope.model.value) {
if ($scope.model.value[n] === false) {
available.push(n);
}
}
return available;
};
function memberGroupController($scope, editorService, memberGroupResource) {
//set the selected to the keys of the dictionary who's value is true
$scope.getSelected = function () {
var selected = [];
@@ -21,16 +10,30 @@
return selected;
};
$scope.addItem = function(item) {
//keep the model up to date
$scope.model.value[item] = true;
};
$scope.removeItem = function (item) {
//keep the model up to date
$scope.model.value[item] = false;
};
$scope.pickGroup = function() {
editorService.memberGroupPicker({
multiPicker: true,
submit: function (model) {
var selectedGroupIds = _.map(model.selectedMemberGroups
? model.selectedMemberGroups
: [model.selectedMemberGroup],
function(id) { return parseInt(id) }
);
memberGroupResource.getByIds(selectedGroupIds).then(function (selectedGroups) {
_.each(selectedGroups, function(group) {
$scope.model.value[group.name] = true;
});
});
editorService.close();
},
close: function () {
editorService.close();
}
});
}
$scope.removeGroup = function (group) {
$scope.model.value[group] = false;
}
}
angular.module('umbraco').controller("Umbraco.PropertyEditors.MemberGroupController", memberGroupController);
angular.module('umbraco').controller("Umbraco.PropertyEditors.MemberGroupController", memberGroupController);
@@ -1,18 +1,11 @@
<div ng-controller="Umbraco.PropertyEditors.MemberGroupController">
<div class="umb-member-group-box">
<h5><localize key="content_notmemberof">Not a member of group(s)</localize></h5>
<ul>
<li ng-repeat="item in getAvailable()">
<a href="" ng-click="addItem(item)">{{item}}</a>
</li>
</ul>
</div>
<div class="umb-member-group-box">
<h5><localize key="content_memberof">Member of group(s)</localize></h5>
<ul>
<li ng-repeat="item in getSelected()">
<a href="" ng-click="removeItem(item)">{{item}}</a>
</li>
</ul>
</div>
<umb-node-preview ng-repeat="group in getSelected() | orderBy"
icon="'icon-users'"
name="group"
allow-remove="true"
on-remove="removeGroup(group)">
</umb-node-preview>
<a href ng-click="pickGroup()" class="umb-node-preview-add" prevent-default>
<localize key="general_add">Add</localize>
</a>
</div>
-13
View File
@@ -213,19 +213,10 @@
<Content Include="Config\Lang\sv-SE.user.xml" />
<Content Include="Config\Lang\zh-CN.user.xml" />
<Content Include="Umbraco\Config\Lang\cs.xml" />
<Content Include="Umbraco\ClientRedirect.aspx" />
<Content Include="Umbraco\Config\Lang\tr.xml" />
<Content Include="Umbraco\Config\Lang\zh_tw.xml" />
<Content Include="Umbraco\create.aspx" />
<Content Include="Umbraco\Developer\Packages\installer.aspx" />
<Content Include="Umbraco\umbraco.aspx" />
<Compile Include="Umbraco\umbraco.aspx.cs">
<DependentUpon>umbraco.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="Umbraco\umbraco.aspx.designer.cs">
<DependentUpon>umbraco.aspx</DependentUpon>
</Compile>
<Content Include="Config\Splashes\booting.aspx" />
<Content Include="Config\Splashes\noNodes.aspx" />
<Content Include="Umbraco\Install\Views\Web.config" />
@@ -321,7 +312,6 @@
</Content>
<Content Include="Umbraco\Config\Lang\ko.xml" />
<Content Include="Umbraco\Dashboard\FeedProxy.aspx" />
<Content Include="Umbraco\endPreview.aspx" />
<Content Include="default.aspx" />
<Content Include="Umbraco\Config\Lang\da.xml">
<SubType>Designer</SubType>
@@ -416,9 +406,6 @@
<Content Include="Umbraco\Js\dualSelectBox.js" />
<Content Include="Umbraco\Js\guiFunctions.js" />
<Content Include="Umbraco\Js\umbracoCheckKeys.js" />
<Content Include="Umbraco\ping.aspx">
<SubType>Form</SubType>
</Content>
<!--<Content Include="Umbraco\users\PermissionEditor.aspx" />-->
<Content Include="Umbraco\Masterpages\default.Master" />
<None Include="web.Template.config">
@@ -1,64 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" Inherits="Umbraco.Web.UI.Pages.UmbracoEnsuredPage" %>
<%--
This page is required because we cannot reload the angular app with a changed Hash since it just detects the hash and doesn't reload.
So this is used purely for a full reload of an angular app with a changed hash.
--%>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Redirecting...</title>
<script type="text/javascript">
var parts = window.location.href.split("?redirectUrl=");
if (parts.length !== 2) {
window.location.href = "/";
}
else {
//This is a genius way of parsing a uri
//https://gist.github.com/jlong/2428561
try {
var parser = document.createElement('a');
parser.href = parts[1];
// This next line may seem redundant but is required to get around a bug in IE
// that doesn't set the parser.hostname or parser.protocol correctly for relative URLs.
// See https://gist.github.com/jlong/2428561#gistcomment-1461205
parser.href = parser.href;
// => "http:"
if (!parser.protocol || (parser.protocol.toLowerCase() !== "http:" && parser.protocol.toLowerCase() !== "https:")) {
throw "invalid protocol";
};
// => "example.com"
if (!parser.hostname || parser.hostname === "") {
throw "invalid hostname";
}
//parser.port; // => "3000"
//parser.pathname => "/pathname/"
//parser.search => "?search=test"
// => "#hash"
if (parser.hash && parser.hash.indexOf("#/developer/framed/") !== 0) {
throw "invalid hash";
}
//parser.host; // => "example.com:3000"
if (parser.host === window.location.host) {
window.location.href = parts[1];
}
} catch (e) {
alert(e);
}
}
</script>
</head>
<body>
<small>Redirecting...</small>
</body>
</html>
@@ -14,7 +14,7 @@
<key alias="createPackage">Vytvořit balíček</key>
<key alias="delete">Odstranit</key>
<key alias="disable">Deaktivovat</key>
<key alias="emptyTrashcan">Vyprázdnit koš</key>
<key alias="emptyRecycleBin">Vyprázdnit koš</key>
<key alias="exportDocumentType">Exportovat typ dokumentu</key>
<key alias="importDocumentType">Importovat typ dokumentu</key>
<key alias="importPackage">Importovat balíček</key>
@@ -210,7 +210,6 @@
<key alias="closeThisWindow">Zavřít toto okno</key>
<key alias="confirmdelete">Jste si jistí. že chcete odstranit</key>
<key alias="confirmdisable">Jste si jistí, že chcete deaktivovat</key>
<key alias="confirmEmptyTrashcan">Zatrhněte, prosím, tento box, abyste potvrdili odstranění %0% položek</key>
<key alias="confirmlogout">Jste si jistí?</key>
<key alias="confirmSure">Jste si jistí?</key>
<key alias="cut">Vyjmout</key>
@@ -992,4 +991,4 @@
<key alias="yourHistory" version="7.0">Vaše nedávná historie</key>
<key alias="sessionExpires" version="7.0">Relace vyprší za</key>
</area>
</language>
</language>
@@ -15,7 +15,7 @@
<key alias="createGroup">Opret gruppe</key>
<key alias="delete">Slet</key>
<key alias="disable">Deaktivér</key>
<key alias="emptyTrashcan">Tøm papirkurv</key>
<key alias="emptyRecycleBin">Tøm papirkurv</key>
<key alias="enable">Aktivér</key>
<key alias="exportDocumentType">Eksportér dokumenttype</key>
<key alias="importDocumentType">Importér dokumenttype</key>
@@ -333,7 +333,6 @@
<key alias="closeThisWindow">Luk denne dialog</key>
<key alias="confirmdelete">Er du sikker på at du vil slette</key>
<key alias="confirmdisable">Er du sikker på du vil deaktivere</key>
<key alias="confirmEmptyTrashcan">Afkryds venligst denne boks for at bekræfte sletningen af %0% enhed(er)</key>
<key alias="confirmlogout">Er du sikker på at du vil forlade Umbraco?</key>
<key alias="confirmSure">Er du sikker?</key>
<key alias="cut">Klip</key>
@@ -14,7 +14,7 @@
<key alias="createPackage">Paket erstellen</key>
<key alias="delete">Löschen</key>
<key alias="disable">Deaktivieren</key>
<key alias="emptyTrashcan">Papierkorb leeren</key>
<key alias="emptyRecycleBin">Papierkorb leeren</key>
<key alias="exportDocumentType">Dokumenttyp exportieren</key>
<key alias="importDocumentType">Dokumenttyp importieren</key>
<key alias="importPackage">Paket importieren</key>
@@ -222,7 +222,6 @@
<key alias="closeThisWindow">Fenster schließen</key>
<key alias="confirmdelete">Sind Sie sicher?</key>
<key alias="confirmdisable">Deaktivieren bestätigen</key>
<key alias="confirmEmptyTrashcan">Löschen von %0% Element(en) bestätigen</key>
<key alias="confirmlogout">Sind Sie sicher?</key>
<key alias="confirmSure">Sind Sie sicher?</key>
<key alias="cut">Ausschneiden</key>
@@ -881,7 +880,7 @@ das Dokument '%1%' wurde von '%2%' zur Übersetzung in '%5%' freigegeben.
Zum Bearbeiten verwenden Sie bitte diesen Link: http://%3%/translation/details.aspx?id=%4%.
Sie können sich auch alle anstehenden Übersetzungen gesammelt im Umbraco-Verwaltungsbereich anzeigen lassen: http://%3%/Umbraco.aspx
Sie können sich auch alle anstehenden Übersetzungen gesammelt im Umbraco-Verwaltungsbereich anzeigen lassen: http://%3%/umbraco
Einen schönen Tag wünscht
Ihr freundlicher Umbraco-Robot
@@ -977,4 +976,4 @@ Ihr freundlicher Umbraco-Robot
<key alias="yourHistory" version="7.0">Ihr Verlauf</key>
<key alias="sessionExpires" version="7.0">Sitzung läuft ab in</key>
</area>
</language>
</language>
@@ -16,7 +16,7 @@
<key alias="createGroup">Create group</key>
<key alias="delete">Delete</key>
<key alias="disable">Disable</key>
<key alias="emptyTrashcan">Empty recycle bin</key>
<key alias="emptyRecycleBin">Empty recycle bin</key>
<key alias="enable">Enable</key>
<key alias="exportDocumentType">Export Document Type</key>
<key alias="importDocumentType">Import Document Type</key>
@@ -350,7 +350,6 @@
<key alias="closeThisWindow">Close this window</key>
<key alias="confirmdelete">Are you sure you want to delete</key>
<key alias="confirmdisable">Are you sure you want to disable</key>
<key alias="confirmEmptyTrashcan">Please check this box to confirm deletion of %0% item(s)</key>
<key alias="confirmlogout">Are you sure?</key>
<key alias="confirmSure">Are you sure?</key>
<key alias="cut">Cut</key>
@@ -1816,6 +1815,7 @@ To manage your website, simply open the Umbraco back office and start adding con
</area>
<area alias="validation">
<key alias="validation">Validation</key>
<key alias="noValidation">No validation</key>
<key alias="validateAsEmail">Validate as an email address</key>
<key alias="validateAsNumber">Validate as a number</key>
<key alias="validateAsUrl">Validate as a URL</key>
@@ -16,7 +16,7 @@
<key alias="createGroup">Create group</key>
<key alias="delete">Delete</key>
<key alias="disable">Disable</key>
<key alias="emptyTrashcan">Empty recycle bin</key>
<key alias="emptyRecycleBin">Empty recycle bin</key>
<key alias="enable">Enable</key>
<key alias="exportDocumentType">Export Document Type</key>
<key alias="importDocumentType">Import Document Type</key>
@@ -147,8 +147,9 @@
<key alias="atViewingFor">Viewing for</key>
<key alias="delete">Content deleted</key>
<key alias="unpublish">Content unpublished</key>
<key alias="publish">Content saved and Published</key>
<key alias="publishvariant">Content saved and published for languages: %0% </key>
<key alias="unpublishvariant">Content unpublished for languages: %0% </key>
<key alias="publish">Content published</key>
<key alias="publishvariant">Content published for languages: %0% </key>
<key alias="save">Content saved</key>
<key alias="savevariant">Content saved for languages: %0%</key>
<key alias="move">Content moved</key>
@@ -165,10 +166,12 @@
<key alias="smallSaveVariant">Save</key>
<key alias="smallDelete">Delete</key>
<key alias="smallUnpublish">Unpublish</key>
<key alias="smallUnpublishVariant">Unpublish</key>
<key alias="smallRollBack">Rollback</key>
<key alias="smallSendToPublish">Send To Publish</key>
<key alias="smallSendToPublishVariant">Send To Publish</key>
<key alias="smallSort">Sort</key>
<key alias="historyIncludingVariants">History (all variants)</key>
</area>
<area alias="changeDocType">
<key alias="changeDocTypeInstruction">To change the document type for the selected content, first select from the list of valid types for this location.</key>
@@ -373,7 +376,6 @@
<key alias="closeThisWindow">Close this window</key>
<key alias="confirmdelete">Are you sure you want to delete</key>
<key alias="confirmdisable">Are you sure you want to disable</key>
<key alias="confirmEmptyTrashcan">Please check this box to confirm deletion of %0% item(s)</key>
<key alias="confirmlogout">Are you sure?</key>
<key alias="confirmSure">Are you sure?</key>
<key alias="cut">Cut</key>
@@ -15,7 +15,7 @@
<key alias="createGroup">Crear grupo</key>
<key alias="delete">Borrar</key>
<key alias="disable">Deshabilitar</key>
<key alias="emptyTrashcan">Vaciar Papelera</key>
<key alias="emptyRecycleBin">Vaciar Papelera</key>
<key alias="enable">Activar</key>
<key alias="exportDocumentType">Exportar Documento (tipo)</key>
<key alias="importDocumentType">Importar Documento (tipo)</key>
@@ -296,7 +296,6 @@
<key alias="closeThisWindow">Cerrar esta ventana</key>
<key alias="confirmdelete">Estás seguro que quieres borrar</key>
<key alias="confirmdisable">Estás seguro que quieres deshabilitar</key>
<key alias="confirmEmptyTrashcan">Por favor selecciona esta casilla para confirmar la eliminación de %0% entrada(s)</key>
<key alias="confirmlogout">¿Estás seguro?</key>
<key alias="confirmSure">¿Estás seguro?</key>
<key alias="cut">Cortar</key>
@@ -16,7 +16,7 @@
<key alias="createPackage">Créer un package</key>
<key alias="delete">Supprimer</key>
<key alias="disable">Désactiver</key>
<key alias="emptyTrashcan">Vider la corbeille</key>
<key alias="emptyRecycleBin">Vider la corbeille</key>
<key alias="enable">Activer</key>
<key alias="exportDocumentType">Exporter le type de document</key>
<key alias="importDocumentType">Importer un type de document</key>
@@ -310,7 +310,6 @@
<key alias="closeThisWindow">Fermer cette fenêtre</key>
<key alias="confirmdelete">Êtes-vous certain(e) de vouloir supprimer</key>
<key alias="confirmdisable">Êtes-vous certain(e) de vouloir désactiver</key>
<key alias="confirmEmptyTrashcan">Cochez cette case pour confirmer la suppression de %0% élément(s)</key>
<key alias="confirmlogout">Êtes-vous certain(e)?</key>
<key alias="confirmSure">Êtes-vous certain(e)?</key>
<key alias="cut">Couper</key>
@@ -13,7 +13,7 @@
<key alias="createPackage">צור חבילה</key>
<key alias="delete">מחק</key>
<key alias="disable">נטרל</key>
<key alias="emptyTrashcan">רוקן סל מיחזור</key>
<key alias="emptyRecycleBin">רוקן סל מיחזור</key>
<key alias="exportDocumentType">ייצא סוג קובץ</key>
<key alias="importDocumentType">ייבא סוג מסמך</key>
<key alias="importPackage">ייבא חבילה</key>
@@ -159,7 +159,6 @@
<key alias="closeThisWindow">סגור חלון זה</key>
<key alias="confirmdelete">האם הינך בטוח שברצונך למחוק זאת?</key>
<key alias="confirmdisable">האם הינך בטוח שברצונך לכבות זאת?</key>
<key alias="confirmEmptyTrashcan">סמן תיבה זו לאשר מחיקה סופית של %0% פריט/ים</key>
<key alias="confirmlogout">האם הינך בטוח?</key>
<key alias="confirmSure">האם אתה בטוח?</key>
<key alias="cut">גזור</key>
@@ -888,4 +887,4 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="userTypes">סוגי משתמש</key>
<key alias="writer">כותב</key>
</area>
</language>
</language>
@@ -13,7 +13,7 @@
<key alias="createPackage">Crea pacchetto</key>
<key alias="delete">Cancella</key>
<key alias="disable">Disabilita</key>
<key alias="emptyTrashcan">Svuota il cestino</key>
<key alias="emptyRecycleBin">Svuota il cestino</key>
<key alias="exportDocumentType">Esporta il tipo di documento</key>
<key alias="importDocumentType">Importa il tipo di documento</key>
<key alias="importPackage">Importa il pacchetto</key>
@@ -164,7 +164,6 @@
<key alias="closeThisWindow">Chiudi questa finestra</key>
<key alias="confirmdelete"><![CDATA[Sei sicuro di voler eliminare?]]></key>
<key alias="confirmdisable"><![CDATA[Sei sicuro di voler disabilitare?]]></key>
<key alias="confirmEmptyTrashcan"><![CDATA[Cliccare per confermare la cancellazione di %0% elemento(i)]]></key>
<key alias="confirmlogout"><![CDATA[Sei sicuro?]]></key>
<key alias="confirmSure"><![CDATA[Sei sicuro?]]></key>
<key alias="cut">Taglia</key>
@@ -877,4 +876,4 @@ Per gestire il tuo sito web, è sufficiente aprire il back office di Umbraco e i
<key alias="userTypes"><![CDATA[Tipi Utente]]></key>
<key alias="writer">Writer</key>
</area>
</language>
</language>
@@ -14,7 +14,7 @@
<key alias="createPackage">パッケージの作成</key>
<key alias="delete">削除</key>
<key alias="disable">無効</key>
<key alias="emptyTrashcan">ごみ箱を空にする</key>
<key alias="emptyRecycleBin">ごみ箱を空にする</key>
<key alias="exportDocumentType">ドキュメントタイプの書出</key>
<key alias="importDocumentType">ドキュメントタイプの読込</key>
<key alias="importPackage">パッケージの読み込み</key>
@@ -224,7 +224,6 @@
<key alias="closeThisWindow">このウィンドウを閉じる</key>
<key alias="confirmdelete">削除しますか?</key>
<key alias="confirmdisable">無効にしますか?</key>
<key alias="confirmEmptyTrashcan">これらの %0% 個の項目を削除する場合は、チェックボックスにチェックを入れてください</key>
<key alias="confirmlogout">ログアウトしますか?</key>
<key alias="confirmSure">本当にいいですか?</key>
<key alias="cut">切り取り</key>
@@ -1132,4 +1131,4 @@ Runwayをインストールして作られた新しいウェブサイトがど
<key alias="enterCustomValidation">... またはカスタム検証を入力</key>
<key alias="fieldIsMandatory">必須フィールドです</key>
</area>
</language>
</language>
@@ -13,7 +13,7 @@
<key alias="createPackage">패키지 새로 만들기</key>
<key alias="delete">삭제</key>
<key alias="disable">비활성</key>
<key alias="emptyTrashcan">휴지통 비우기</key>
<key alias="emptyRecycleBin">휴지통 비우기</key>
<key alias="exportDocumentType">추출 문서 유형</key>
<key alias="importDocumentType">등록 문서 유형</key>
<key alias="importPackage">패키지 등록</key>
@@ -158,7 +158,6 @@
<key alias="closeThisWindow">이창 닫기</key>
<key alias="confirmdelete">정말로 삭제하시겠습니까?</key>
<key alias="confirmdisable">정말로 비활성화하시겠습니까?</key>
<key alias="confirmEmptyTrashcan">%0% 항목(들)을 삭제하시려면 이 박스를 체크하세요</key>
<key alias="confirmlogout">로그아웃 하시겠습니까?</key>
<key alias="confirmSure">확실합니까?</key>
<key alias="cut">TRANSLATE ME: 'Cut'</key>
@@ -868,4 +867,4 @@
<key alias="userTypes">사용자 타입</key>
<key alias="writer">작성자</key>
</area>
</language>
</language>
@@ -14,7 +14,7 @@
<key alias="createPackage">Opprett pakke</key>
<key alias="delete">Slett</key>
<key alias="disable">Deaktiver</key>
<key alias="emptyTrashcan">Tøm papirkurv</key>
<key alias="emptyRecycleBin">Tøm papirkurv</key>
<key alias="exportDocumentType">Eksporter dokumenttype</key>
<key alias="importDocumentType">Importer dokumenttype</key>
<key alias="importPackage">Importer pakke</key>
@@ -218,7 +218,6 @@
<key alias="closeThisWindow">Lukk dette vinduet</key>
<key alias="confirmdelete">Er du sikker på at du vil slette</key>
<key alias="confirmdisable">Er du sikker på at du vil deaktivere</key>
<key alias="confirmEmptyTrashcan">Vennligst kryss av i denne boksen for å bekrefte sletting av %0% element(er)</key>
<key alias="confirmlogout">Er du sikker på at du vil forlate Umbraco?</key>
<key alias="confirmSure">Er du sikker?</key>
<key alias="cut">Klipp ut</key>
@@ -961,4 +960,4 @@ Vennlig hilsen Umbraco roboten
<key alias="yourHistory" version="7.0">Din historikk</key>
<key alias="sessionExpires" version="7.0">Sesjonen utløper om</key>
</area>
</language>
</language>
@@ -14,7 +14,7 @@
<key alias="createPackage">Nieuwe package</key>
<key alias="delete">Verwijderen</key>
<key alias="disable">Uitschakelen</key>
<key alias="emptyTrashcan">Prullenbak leegmaken</key>
<key alias="emptyRecycleBin">Prullenbak leegmaken</key>
<key alias="exportDocumentType">Documenttype exporteren</key>
<key alias="importDocumentType">Documenttype importeren</key>
<key alias="importPackage">Package importeren</key>
@@ -249,7 +249,6 @@
<key alias="closeThisWindow">Sluit dit venster</key>
<key alias="confirmdelete">Weet je zeker dat je dit wilt verwijderen</key>
<key alias="confirmdisable">Weet je zeker dat je dit wilt uitschakelen</key>
<key alias="confirmEmptyTrashcan">Vink aub dit keuzevak aan om het verwijderen van %0% item(s) te bevestigen</key>
<key alias="confirmlogout">Weet je het zeker?</key>
<key alias="confirmSure">Weet je het zeker?</key>
<key alias="cut">Knippen</key>
@@ -15,7 +15,7 @@
<key alias="createGroup">Stwórz grupę</key>
<key alias="delete">Usuń</key>
<key alias="disable">Deaktywuj</key>
<key alias="emptyTrashcan">Opróżnij kosz</key>
<key alias="emptyRecycleBin">Opróżnij kosz</key>
<key alias="enable">Aktywuj</key>
<key alias="exportDocumentType">Eksportuj typ dokumentu</key>
<key alias="importDocumentType">Importuj typ dokumentu</key>
@@ -298,7 +298,6 @@
<key alias="closeThisWindow">Zamknij to okno</key>
<key alias="confirmdelete">Jesteś pewny, że chcesz usunąć</key>
<key alias="confirmdisable">Jesteś pewny, że chcesz wyłączyć</key>
<key alias="confirmEmptyTrashcan">Proszę zaznaczyć, aby potwierdzić usunięcie %0% elementów.</key>
<key alias="confirmlogout">Jesteś pewny?</key>
<key alias="confirmSure">Jesteś pewny?</key>
<key alias="cut">Wytnij</key>
@@ -13,7 +13,7 @@
<key alias="createPackage">Criar Pacote</key>
<key alias="delete">Remover</key>
<key alias="disable">Desabilitar</key>
<key alias="emptyTrashcan">Esvaziar Lixeira</key>
<key alias="emptyRecycleBin">Esvaziar Lixeira</key>
<key alias="exportDocumentType">Exportar Tipo de Documento</key>
<key alias="importDocumentType">Importar Tipo de Documento</key>
<key alias="importPackage">Importar Pacote</key>
@@ -158,7 +158,6 @@
<key alias="closeThisWindow">Fechar esta janela</key>
<key alias="confirmdelete">Certeza em remover</key>
<key alias="confirmdisable">Certeza em desabilitar</key>
<key alias="confirmEmptyTrashcan">Favor selecionar esta caixa para confirmar a remoção de %0% item(s)</key>
<key alias="confirmlogout">Tem certeza</key>
<key alias="confirmSure">Tem certeza?</key>
<key alias="cut">Cortar</key>
@@ -857,4 +856,4 @@ Você pode publicar esta página e todas suas sub-páginas ao selecionar <em>pub
<key alias="userTypes">Tipos de usuários</key>
<key alias="writer">Escrevente</key>
</area>
</language>
</language>
@@ -17,7 +17,7 @@
<key alias="defaultValue">Значение по умолчанию</key>
<key alias="delete">Удалить</key>
<key alias="disable">Отключить</key>
<key alias="emptyTrashcan">Очистить корзину</key>
<key alias="emptyRecycleBin">Очистить корзину</key>
<key alias="enable">Включить</key>
<key alias="export">Экспорт</key>
<key alias="exportDocumentType">Экспортировать</key>
@@ -346,7 +346,6 @@
<key alias="closeThisWindow">Закрыть это окно</key>
<key alias="confirmdelete">Вы уверены, что хотите удалить</key>
<key alias="confirmdisable">Вы уверены, что хотите запретить</key>
<key alias="confirmEmptyTrashcan">Пожалуйста, подтвердите удаление из корзины %0% элементов</key>
<key alias="confirmlogout">Вы уверены?</key>
<key alias="confirmSure">Вы уверены?</key>
<key alias="cut">Вырезать</key>
@@ -15,7 +15,7 @@
<key alias="defaultValue">Standardvärde</key>
<key alias="delete">Ta bort</key>
<key alias="disable">Avaktivera</key>
<key alias="emptyTrashcan">Töm papperskorgen</key>
<key alias="emptyRecycleBin">Töm papperskorgen</key>
<key alias="exportDocumentType">Exportera dokumenttyp</key>
<key alias="importDocumentType">Importera dokumenttyp</key>
<key alias="importPackage">Importera paket</key>
@@ -216,7 +216,6 @@
<key alias="closeThisWindow">Stäng fönstret</key>
<key alias="confirmdelete">Är du säker på att du vill ta bort</key>
<key alias="confirmdisable">Är du säker på att du vill avaktivera</key>
<key alias="confirmEmptyTrashcan">Kryssa i denna ruta för att bekräfta att %0% objekt tas bort</key>
<key alias="confirmlogout">Är du säker?</key>
<key alias="confirmSure">Är du säker?</key>
<key alias="cut">Klipp ut</key>
@@ -904,4 +903,4 @@
<key alias="yourHistory">Din nuvarande historik</key>
<key alias="yourProfile">Din profil</key>
</area>
</language>
</language>
@@ -14,7 +14,7 @@
<key alias="createPackage">Paket Oluştur</key>
<key alias="delete">Sil</key>
<key alias="disable">Devre Dışı Bırak</key>
<key alias="emptyTrashcan">Geri Dönüşümü Boşat</key>
<key alias="emptyRecycleBin">Geri Dönüşümü Boşat</key>
<key alias="exportDocumentType">Belge Türü Çıkart</key>
<key alias="importDocumentType">Belge Türü Al</key>
<key alias="importPackage">Paket Ekle</key>
@@ -191,7 +191,6 @@
<key alias="closeThisWindow">Bu pencereyi kapatın</key>
<key alias="confirmdelete">Silmek istediğine emin misin</key>
<key alias="confirmdisable">Eğer devre dışı bırakmak istediğinizden emin misiniz</key>
<key alias="confirmEmptyTrashcan">%0% öğe(lerin) silinmesi onaylamak için bu kutuyu kontrol edin</key>
<key alias="confirmlogout">Emin misiniz?</key>
<key alias="confirmSure">Emin misiniz?</key>
<key alias="cut">Kes</key>
@@ -14,7 +14,7 @@
<key alias="createPackage">创建扩展包</key>
<key alias="delete">删除</key>
<key alias="disable">禁用</key>
<key alias="emptyTrashcan">清空回收站</key>
<key alias="emptyRecycleBin">清空回收站</key>
<key alias="exportDocumentType">导出文档类型</key>
<key alias="importDocumentType">导入文档类型</key>
<key alias="importPackage">导入扩展包</key>
@@ -237,7 +237,6 @@
<key alias="closeThisWindow">关闭窗口</key>
<key alias="confirmdelete">您确定要删除吗</key>
<key alias="confirmdisable">您确定要禁用吗</key>
<key alias="confirmEmptyTrashcan">单击此框确定删除%0%项</key>
<key alias="confirmlogout">您确定吗?</key>
<key alias="confirmSure">您确定吗?</key>
<key alias="cut">剪切</key>
@@ -14,7 +14,7 @@
<key alias="createPackage">創建擴展包</key>
<key alias="delete">刪除</key>
<key alias="disable">禁用</key>
<key alias="emptyTrashcan">清空回收站</key>
<key alias="emptyRecycleBin">清空回收站</key>
<key alias="exportDocumentType">匯出文檔類型</key>
<key alias="importDocumentType">導入文檔類型</key>
<key alias="importPackage">導入擴展包</key>
@@ -234,7 +234,6 @@
<key alias="closeThisWindow">關閉窗口</key>
<key alias="confirmdelete">您確定要刪除嗎</key>
<key alias="confirmdisable">您確定要禁用嗎</key>
<key alias="confirmEmptyTrashcan">按一下此框確定刪除%0%項</key>
<key alias="confirmlogout">您確定嗎?</key>
<key alias="confirmSure">您確定嗎?</key>
<key alias="cut">剪切</key>
@@ -1,3 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" Inherits="umbraco.presentation.endPreview" %>
<!-- -->
-2
View File
@@ -1,2 +0,0 @@
<%@ Page language="c#" AutoEventWireup="True" %>
I'm alive!
-2
View File
@@ -1,2 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="umbraco.aspx.cs" Inherits="Umbraco.Web.UI.Umbraco.umbraco" %>
@@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
namespace Umbraco.Web.UI.Umbraco
{
public partial class umbraco : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Status = "301 Moved Permanently";
Response.AddHeader("Location", Current.Config.Global().Path);
}
}
}
-15
View File
@@ -1,15 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Web.UI.Umbraco {
public partial class umbraco {
}
}
@@ -41,7 +41,7 @@
<!-- The html injected into a (x)html page if Umbraco is running in preview mode -->
<PreviewBadge>
<![CDATA[
<a id="umbracoPreviewBadge" style="z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/endPreview.aspx?redir={1}'"><span style="display:none;">In Preview Mode - click to end</span></a>
<a id="umbracoPreviewBadge" style="z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/preview/end?redir={1}'"><span style="display:none;">In Preview Mode - click to end</span></a>
]]></PreviewBadge>
<!-- How Umbraco should handle errors during macro execution. Can be one of the following values:
@@ -76,7 +76,7 @@
<!-- The html injected into a (x)html page if Umbraco is running in preview mode -->
<PreviewBadge>
<![CDATA[
<a id="umbracoPreviewBadge" style="z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/endPreview.aspx?redir={1}'"><span style="display:none;">In Preview Mode - click to end</span></a>
<a id="umbracoPreviewBadge" style="z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/preview/end?redir={1}'"><span style="display:none;">In Preview Mode - click to end</span></a>
]]></PreviewBadge>
+1 -1
View File
@@ -1,2 +1,2 @@
<%@ Page language="c#" Codebehind="default.aspx.cs" AutoEventWireup="True" Inherits="umbraco.UmbracoDefault" trace="true" validateRequest="false" %>
<%@ Page language="c#" AutoEventWireup="True" Inherits="umbraco.UmbracoDefault" trace="true" validateRequest="false" %>
@@ -14,7 +14,7 @@
<key alias="createPackage">Opprett pakke</key>
<key alias="delete">Slett</key>
<key alias="disable">Deaktiver</key>
<key alias="emptyTrashcan">Tøm papirkurv</key>
<key alias="emptyRecycleBin">Tøm papirkurv</key>
<key alias="exportDocumentType">Eksporter dokumenttype</key>
<key alias="importDocumentType">Importer dokumenttype</key>
<key alias="importPackage">Importer pakke</key>
@@ -218,7 +218,6 @@
<key alias="closeThisWindow">Lukk dette vinduet</key>
<key alias="confirmdelete">Er du sikker på at du vil slette</key>
<key alias="confirmdisable">Er du sikker på at du vil deaktivere</key>
<key alias="confirmEmptyTrashcan">Vennligst kryss av i denne boksen for å bekrefte sletting av %0% element(er)</key>
<key alias="confirmlogout">Er du sikker på at du vil forlate Umbraco?</key>
<key alias="confirmSure">Er du sikker?</key>
<key alias="cut">Klipp ut</key>
@@ -961,4 +960,4 @@ Vennlig hilsen Umbraco roboten
<key alias="yourHistory" version="7.0">Din historikk</key>
<key alias="sessionExpires" version="7.0">Sesjonen utløper om</key>
</area>
</language>
</language>
@@ -14,7 +14,7 @@
<key alias="createPackage">創建擴展包</key>
<key alias="delete">刪除</key>
<key alias="disable">禁用</key>
<key alias="emptyTrashcan">清空回收站</key>
<key alias="emptyRecycleBin">清空回收站</key>
<key alias="exportDocumentType">匯出文檔類型</key>
<key alias="importDocumentType">導入文檔類型</key>
<key alias="importPackage">導入擴展包</key>
@@ -234,7 +234,6 @@
<key alias="closeThisWindow">關閉窗口</key>
<key alias="confirmdelete">您確定要刪除嗎</key>
<key alias="confirmdisable">您確定要禁用嗎</key>
<key alias="confirmEmptyTrashcan">按一下此框確定刪除%0%項</key>
<key alias="confirmlogout">您確定嗎?</key>
<key alias="confirmSure">您確定嗎?</key>
<key alias="cut">剪切</key>
+4 -1
View File
@@ -486,7 +486,10 @@ namespace Umbraco.Web.Editors
var pagedResult = new PagedResult<EntityBasic>(totalRecords, pageNumber, pageSize)
{
Items = entities.Select(Mapper.Map<EntityBasic>)
Items = entities.Select(entity => Mapper.Map<IEntitySlim, EntityBasic>(entity, options =>
options.AfterMap((src, dest) => { dest.AdditionalData["hasChildren"] = src.HasChildren; })
)
)
};
return pagedResult;
@@ -73,7 +73,7 @@ namespace Umbraco.Web.Editors
if (!msg.IsSuccessStatusCode)
throw new HttpResponseException(msg);
var results = TryParseLuceneQuery(query)
var results = Examine.ExamineExtensions.TryParseLuceneQuery(query)
? searcher.Search(searcher.CreateCriteria().RawQuery(query), maxResults: pageSize * (pageIndex + 1))
: searcher.Search(query, true, maxResults: pageSize * (pageIndex + 1));
@@ -92,28 +92,7 @@ namespace Umbraco.Web.Editors
};
}
private bool TryParseLuceneQuery(string query)
{
//TODO: I'd assume there would be a more strict way to parse the query but not that i can find yet, for now we'll
// also do this rudimentary check
if (!query.Contains(":"))
return false;
try
{
//This will pass with a plain old string without any fields, need to figure out a way to have it properly parse
var parsed = new QueryParser(Version.LUCENE_30, "nodeName", new KeywordAnalyzer()).Parse(query);
return true;
}
catch (ParseException)
{
return false;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Check if the index has been rebuilt
@@ -0,0 +1,33 @@
using System.Runtime.Serialization;
using System.Web.Http;
using Umbraco.Web.WebApi;
namespace Umbraco.Web.Editors
{
// fixme
// this is not authenticated, and therefore public, and therefore reveals we
// are running Umbraco - but, all requests should come from localhost really,
// so there should be a way to 404 when the request comes from the outside.
public class KeepAliveController : UmbracoApiController
{
[HttpGet]
public KeepAlivePingResult Ping()
{
return new KeepAlivePingResult
{
Success = true,
Message = "I'm alive!"
};
}
}
public class KeepAlivePingResult
{
[DataMember(Name = "success")]
public bool Success { get; set; }
[DataMember(Name = "message")]
public string Message { get; set; }
}
}
@@ -36,6 +36,17 @@ namespace Umbraco.Web.Editors
return dto;
}
public IEnumerable<MemberGroupDisplay> GetByIds([FromUri]int[] ids)
{
if (_provider.IsUmbracoMembershipProvider())
{
return Services.MemberGroupService.GetByIds(ids)
.Select(Mapper.Map<IMemberGroup, MemberGroupDisplay>);
}
return Enumerable.Empty<MemberGroupDisplay>();
}
[HttpDelete]
[HttpPost]
public HttpResponseMessage DeleteById(int id)
@@ -88,5 +88,23 @@ namespace Umbraco.Web.Editors
// if (string.IsNullOrEmpty(editor)) throw new ArgumentNullException(nameof(editor));
// return View(_globalSettings.Path.EnsureEndsWith('/') + "Views/Preview/" + editor.Replace(".html", string.Empty) + ".cshtml");
//}
public ActionResult End(string redir = null)
{
var previewToken = Request.GetPreviewCookieValue();
var service = Current.PublishedSnapshotService;
service.ExitPreview(previewToken);
System.Web.HttpContext.Current.ExpireCookie(Constants.Web.PreviewCookieName);
if (Uri.IsWellFormedUriString(redir, UriKind.Relative)
&& redir.StartsWith("//") == false
&& Uri.TryCreate(redir, UriKind.Relative, out Uri url))
{
return Redirect(url.ToString());
}
return Redirect("/");
}
}
}
@@ -18,26 +18,26 @@ namespace Umbraco.Web.Editors
[JsonCamelCaseFormatter]
public class TemplateQueryController : UmbracoAuthorizedJsonController
{
private IEnumerable<OperathorTerm> Terms
private IEnumerable<OperatorTerm> Terms
{
get
{
return new List<OperathorTerm>()
return new List<OperatorTerm>()
{
new OperathorTerm(Services.TextService.Localize("template/is"), Operathor.Equals, new [] {"string"}),
new OperathorTerm(Services.TextService.Localize("template/isNot"), Operathor.NotEquals, new [] {"string"}),
new OperathorTerm(Services.TextService.Localize("template/before"), Operathor.LessThan, new [] {"datetime"}),
new OperathorTerm(Services.TextService.Localize("template/beforeIncDate"), Operathor.LessThanEqualTo, new [] {"datetime"}),
new OperathorTerm(Services.TextService.Localize("template/after"), Operathor.GreaterThan, new [] {"datetime"}),
new OperathorTerm(Services.TextService.Localize("template/afterIncDate"), Operathor.GreaterThanEqualTo, new [] {"datetime"}),
new OperathorTerm(Services.TextService.Localize("template/equals"), Operathor.Equals, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/doesNotEqual"), Operathor.NotEquals, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/contains"), Operathor.Contains, new [] {"string"}),
new OperathorTerm(Services.TextService.Localize("template/doesNotContain"), Operathor.NotContains, new [] {"string"}),
new OperathorTerm(Services.TextService.Localize("template/greaterThan"), Operathor.GreaterThan, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/greaterThanEqual"), Operathor.GreaterThanEqualTo, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/lessThan"), Operathor.LessThan, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/lessThanEqual"), Operathor.LessThanEqualTo, new [] {"int"})
new OperatorTerm(Services.TextService.Localize("template/is"), Operator.Equals, new [] {"string"}),
new OperatorTerm(Services.TextService.Localize("template/isNot"), Operator.NotEquals, new [] {"string"}),
new OperatorTerm(Services.TextService.Localize("template/before"), Operator.LessThan, new [] {"datetime"}),
new OperatorTerm(Services.TextService.Localize("template/beforeIncDate"), Operator.LessThanEqualTo, new [] {"datetime"}),
new OperatorTerm(Services.TextService.Localize("template/after"), Operator.GreaterThan, new [] {"datetime"}),
new OperatorTerm(Services.TextService.Localize("template/afterIncDate"), Operator.GreaterThanEqualTo, new [] {"datetime"}),
new OperatorTerm(Services.TextService.Localize("template/equals"), Operator.Equals, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/doesNotEqual"), Operator.NotEquals, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/contains"), Operator.Contains, new [] {"string"}),
new OperatorTerm(Services.TextService.Localize("template/doesNotContain"), Operator.NotContains, new [] {"string"}),
new OperatorTerm(Services.TextService.Localize("template/greaterThan"), Operator.GreaterThan, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/greaterThanEqual"), Operator.GreaterThanEqualTo, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/lessThan"), Operator.LessThan, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/lessThanEqual"), Operator.LessThanEqualTo, new [] {"int"})
};
}
}
@@ -67,6 +67,7 @@ namespace Umbraco.Web.Editors
sb.Append("Model.Root()");
//fixme: This timer thing is not correct, it's definitely not timing the resulting query, the timer really isn't important and might as well be removed
var timer = new Stopwatch();
timer.Start();
@@ -122,6 +122,8 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore())
.AfterMap((src, dest) =>
{
//TODO: Properly map this (not aftermap)
//get the icon if there is one
dest.Icon = src.Values.ContainsKey(UmbracoExamineIndex.IconFieldName)
? src.Values[UmbracoExamineIndex.IconFieldName]
@@ -1,6 +1,6 @@
namespace Umbraco.Web.Models.TemplateQuery
{
public enum Operathor
public enum Operator
{
Equals = 1,
NotEquals = 2,
@@ -2,24 +2,24 @@
namespace Umbraco.Web.Models.TemplateQuery
{
public class OperathorTerm
public class OperatorTerm
{
public OperathorTerm()
public OperatorTerm()
{
Name = "is";
Operathor = Operathor.Equals;
Operator = Operator.Equals;
AppliesTo = new [] { "string" };
}
public OperathorTerm(string name, Operathor operathor, IEnumerable<string> appliesTo)
public OperatorTerm(string name, Operator @operator, IEnumerable<string> appliesTo)
{
Name = name;
Operathor = operathor;
Operator = @operator;
AppliesTo = appliesTo;
}
public string Name { get; set; }
public Operathor Operathor { get; set; }
public Operator Operator { get; set; }
public IEnumerable<string> AppliesTo { get; set; }
}
}
@@ -4,7 +4,7 @@
{
public PropertyModel Property { get; set; }
public OperathorTerm Term { get; set; }
public OperatorTerm Term { get; set; }
public string ConstraintValue { get; set; }
}
@@ -53,30 +53,30 @@
}
switch (condition.Term.Operathor)
switch (condition.Term.Operator)
{
case Operathor.Equals:
case Operator.Equals:
operand = " == ";
break;
case Operathor.NotEquals:
case Operator.NotEquals:
operand = " != ";
break;
case Operathor.GreaterThan:
case Operator.GreaterThan:
operand = " > ";
break;
case Operathor.GreaterThanEqualTo:
case Operator.GreaterThanEqualTo:
operand = " >= ";
break;
case Operathor.LessThan:
case Operator.LessThan:
operand = " < ";
break;
case Operathor.LessThanEqualTo:
case Operator.LessThanEqualTo:
operand = " <= ";
break;
case Operathor.Contains:
case Operator.Contains:
value = string.Format("{0}{1}.Contains({2})", prefix, condition.Property.Alias, constraintValue);
break;
case Operathor.NotContains:
case Operator.NotContains:
value = string.Format("!{0}{1}.Contains({2})", prefix, condition.Property.Alias, constraintValue);
break;
default :

Some files were not shown because too many files have changed in this diff Show More