Merge remote-tracking branch 'origin/netcore/netcore' into netcore/feature/net5
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Umbraco.Core.Events;
|
||||
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
@@ -28,8 +27,28 @@ namespace Umbraco.Core.DependencyInjection
|
||||
// Register the handler as transient. This ensures that anything can be injected into it.
|
||||
var descriptor = new UniqueServiceDescriptor(typeof(INotificationHandler<TNotification>), typeof(TNotificationHandler), ServiceLifetime.Transient);
|
||||
|
||||
// TODO: Waiting on feedback here https://github.com/umbraco/Umbraco-CMS/pull/9556/files#r548365396 about whether
|
||||
// we perform this duplicate check or not.
|
||||
if (!builder.Services.Contains(descriptor))
|
||||
{
|
||||
builder.Services.Add(descriptor);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a notification async handler against the Umbraco service collection.
|
||||
/// </summary>
|
||||
/// <typeparam name="TNotification">The type of notification.</typeparam>
|
||||
/// <typeparam name="TNotificationAsyncHandler">The type of notification async handler.</typeparam>
|
||||
/// <param name="builder">The Umbraco builder.</param>
|
||||
/// <returns>The <see cref="IUmbracoBuilder"/>.</returns>
|
||||
public static IUmbracoBuilder AddNotificationAsyncHandler<TNotification, TNotificationAsyncHandler>(this IUmbracoBuilder builder)
|
||||
where TNotificationAsyncHandler : INotificationAsyncHandler<TNotification>
|
||||
where TNotification : INotification
|
||||
{
|
||||
// Register the handler as transient. This ensures that anything can be injected into it.
|
||||
var descriptor = new ServiceDescriptor(typeof(INotificationAsyncHandler<TNotification>), typeof(TNotificationAsyncHandler), ServiceLifetime.Transient);
|
||||
|
||||
if (!builder.Services.Contains(descriptor))
|
||||
{
|
||||
builder.Services.Add(descriptor);
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace Umbraco.Core.DependencyInjection
|
||||
|
||||
Services.AddSingleton<ManifestWatcher>();
|
||||
Services.AddSingleton<UmbracoRequestPaths>();
|
||||
this.AddNotificationHandler<UmbracoApplicationStarting, AppPluginsManifestWatcherNotificationHandler>();
|
||||
this.AddNotificationAsyncHandler<UmbracoApplicationStarting, AppPluginsManifestWatcherNotificationHandler>();
|
||||
|
||||
Services.AddUnique<InstallStatusTracker>();
|
||||
|
||||
|
||||
@@ -15,17 +15,30 @@ namespace Umbraco.Core.Events
|
||||
/// </content>
|
||||
public partial class EventAggregator : IEventAggregator
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, NotificationAsyncHandlerWrapper> s_notificationAsyncHandlers
|
||||
= new ConcurrentDictionary<Type, NotificationAsyncHandlerWrapper>();
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, NotificationHandlerWrapper> s_notificationHandlers
|
||||
= new ConcurrentDictionary<Type, NotificationHandlerWrapper>();
|
||||
|
||||
private Task PublishNotificationAsync(INotification notification, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Type notificationType = notification.GetType();
|
||||
NotificationHandlerWrapper handler = s_notificationHandlers.GetOrAdd(
|
||||
NotificationAsyncHandlerWrapper asyncHandler = s_notificationAsyncHandlers.GetOrAdd(
|
||||
notificationType,
|
||||
t => (NotificationAsyncHandlerWrapper)Activator.CreateInstance(typeof(NotificationAsyncHandlerWrapperImpl<>).MakeGenericType(notificationType)));
|
||||
|
||||
return asyncHandler.HandleAsync(notification, cancellationToken, _serviceFactory, PublishCoreAsync);
|
||||
}
|
||||
|
||||
private void PublishNotification(INotification notification)
|
||||
{
|
||||
Type notificationType = notification.GetType();
|
||||
NotificationHandlerWrapper asyncHandler = s_notificationHandlers.GetOrAdd(
|
||||
notificationType,
|
||||
t => (NotificationHandlerWrapper)Activator.CreateInstance(typeof(NotificationHandlerWrapperImpl<>).MakeGenericType(notificationType)));
|
||||
|
||||
return handler.HandleAsync(notification, cancellationToken, _serviceFactory, PublishCoreAsync);
|
||||
asyncHandler.Handle(notification, _serviceFactory, PublishCore);
|
||||
}
|
||||
|
||||
private async Task PublishCoreAsync(
|
||||
@@ -38,9 +51,27 @@ namespace Umbraco.Core.Events
|
||||
await handler(notification, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void PublishCore(
|
||||
IEnumerable<Action<INotification>> allHandlers,
|
||||
INotification notification)
|
||||
{
|
||||
foreach (Action<INotification> handler in allHandlers)
|
||||
{
|
||||
handler(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class NotificationHandlerWrapper
|
||||
{
|
||||
public abstract void Handle(
|
||||
INotification notification,
|
||||
ServiceFactory serviceFactory,
|
||||
Action<IEnumerable<Action<INotification>>, INotification> publish);
|
||||
}
|
||||
|
||||
internal abstract class NotificationAsyncHandlerWrapper
|
||||
{
|
||||
public abstract Task HandleAsync(
|
||||
INotification notification,
|
||||
@@ -49,7 +80,7 @@ namespace Umbraco.Core.Events
|
||||
Func<IEnumerable<Func<INotification, CancellationToken, Task>>, INotification, CancellationToken, Task> publish);
|
||||
}
|
||||
|
||||
internal class NotificationHandlerWrapperImpl<TNotification> : NotificationHandlerWrapper
|
||||
internal class NotificationAsyncHandlerWrapperImpl<TNotification> : NotificationAsyncHandlerWrapper
|
||||
where TNotification : INotification
|
||||
{
|
||||
public override Task HandleAsync(
|
||||
@@ -59,7 +90,7 @@ namespace Umbraco.Core.Events
|
||||
Func<IEnumerable<Func<INotification, CancellationToken, Task>>, INotification, CancellationToken, Task> publish)
|
||||
{
|
||||
IEnumerable<Func<INotification, CancellationToken, Task>> handlers = serviceFactory
|
||||
.GetInstances<INotificationHandler<TNotification>>()
|
||||
.GetInstances<INotificationAsyncHandler<TNotification>>()
|
||||
.Select(x => new Func<INotification, CancellationToken, Task>(
|
||||
(theNotification, theToken) =>
|
||||
x.HandleAsync((TNotification)theNotification, theToken)));
|
||||
@@ -67,4 +98,22 @@ namespace Umbraco.Core.Events
|
||||
return publish(handlers, notification, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal class NotificationHandlerWrapperImpl<TNotification> : NotificationHandlerWrapper
|
||||
where TNotification : INotification
|
||||
{
|
||||
public override void Handle(
|
||||
INotification notification,
|
||||
ServiceFactory serviceFactory,
|
||||
Action<IEnumerable<Action<INotification>>, INotification> publish)
|
||||
{
|
||||
IEnumerable<Action<INotification>> handlers = serviceFactory
|
||||
.GetInstances<INotificationHandler<TNotification>>()
|
||||
.Select(x => new Action<INotification>(
|
||||
(theNotification) =>
|
||||
x.Handle((TNotification)theNotification)));
|
||||
|
||||
publish(handlers, notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,23 @@ namespace Umbraco.Core.Events
|
||||
throw new ArgumentNullException(nameof(notification));
|
||||
}
|
||||
|
||||
PublishNotification(notification);
|
||||
return PublishNotificationAsync(notification, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Publish<TNotification>(TNotification notification)
|
||||
where TNotification : INotification
|
||||
{
|
||||
// TODO: Introduce codegen efficient Guard classes to reduce noise.
|
||||
if (notification == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(notification));
|
||||
}
|
||||
|
||||
PublishNotification(notification);
|
||||
Task.WaitAll(PublishNotificationAsync(notification));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Events
|
||||
public interface IEventAggregator
|
||||
{
|
||||
/// <summary>
|
||||
/// Asynchronously send a notification to multiple handlers
|
||||
/// Asynchronously send a notification to multiple handlers of both sync and async
|
||||
/// </summary>
|
||||
/// <typeparam name="TNotification">The type of notification being handled.</typeparam>
|
||||
/// <param name="notification">The notification object.</param>
|
||||
@@ -21,5 +21,13 @@ namespace Umbraco.Core.Events
|
||||
/// <returns>A task that represents the publish operation.</returns>
|
||||
Task PublishAsync<TNotification>(TNotification notification, CancellationToken cancellationToken = default)
|
||||
where TNotification : INotification;
|
||||
|
||||
/// <summary>
|
||||
/// Synchronously send a notification to multiple handlers of both sync and async
|
||||
/// </summary>
|
||||
/// <typeparam name="TNotification">The type of notification being handled.</typeparam>
|
||||
/// <param name="notification">The notification object.</param>
|
||||
void Publish<TNotification>(TNotification notification)
|
||||
where TNotification : INotification;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,20 @@ namespace Umbraco.Core.Events
|
||||
/// <typeparam name="TNotification">The type of notification being handled.</typeparam>
|
||||
public interface INotificationHandler<in TNotification>
|
||||
where TNotification : INotification
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles a notification
|
||||
/// </summary>
|
||||
/// <param name="notification">The notification</param>
|
||||
void Handle(TNotification notification);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a handler for a async notification.
|
||||
/// </summary>
|
||||
/// <typeparam name="TNotification">The type of notification being handled.</typeparam>
|
||||
public interface INotificationAsyncHandler<in TNotification>
|
||||
where TNotification : INotification
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles a notification
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Runtime
|
||||
/// <summary>
|
||||
/// Starts monitoring AppPlugins directory during debug runs, to restart site when a plugin manifest changes.
|
||||
/// </summary>
|
||||
public sealed class AppPluginsManifestWatcherNotificationHandler : INotificationHandler<UmbracoApplicationStarting>
|
||||
public sealed class AppPluginsManifestWatcherNotificationHandler : INotificationAsyncHandler<UmbracoApplicationStarting>
|
||||
{
|
||||
private readonly ManifestWatcher _manifestWatcher;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Events;
|
||||
@@ -21,7 +19,7 @@ namespace Umbraco.Core.Runtime
|
||||
_globalSettings = globalSettings.Value;
|
||||
}
|
||||
|
||||
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
|
||||
public void Handle(UmbracoApplicationStarting notification)
|
||||
{
|
||||
// ensure we have some essential directories
|
||||
// every other component can then initialize safely
|
||||
@@ -31,7 +29,6 @@ namespace Umbraco.Core.Runtime
|
||||
_ioHelper.EnsurePathExists(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.PartialViews));
|
||||
_ioHelper.EnsurePathExists(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.MacroPartials));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Persistence;
|
||||
@@ -39,7 +37,7 @@ namespace Umbraco.Infrastructure.Cache
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
|
||||
public void Handle(UmbracoApplicationStarting notification)
|
||||
{
|
||||
// The scheduled tasks - TouchServerTask and InstructionProcessTask - run as .NET Core hosted services.
|
||||
// The former (as well as other hosted services that run outside of an HTTP request context) depends on the application URL
|
||||
@@ -50,8 +48,6 @@ namespace Umbraco.Infrastructure.Cache
|
||||
_requestAccessor.EndRequest += EndRequest;
|
||||
|
||||
Startup();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void Startup()
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.ModelsBuilder.Embedded.BackOffice;
|
||||
using Umbraco.ModelsBuilder.Embedded.DependencyInjection;
|
||||
@@ -19,11 +17,10 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
/// <summary>
|
||||
/// Handles the <see cref="UmbracoApplicationStarting"/> notification to disable MB controller features
|
||||
/// </summary>
|
||||
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
|
||||
public void Handle(UmbracoApplicationStarting notification)
|
||||
{
|
||||
// disable the embedded dashboard controller
|
||||
_features.Disabled.Controllers.Add<ModelsBuilderDashboardController>();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -8,7 +7,6 @@ using Umbraco.Configuration;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.ModelsBuilder.Embedded.Building;
|
||||
using Umbraco.Web.Cache;
|
||||
@@ -52,10 +50,9 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
/// <summary>
|
||||
/// Handles the <see cref="UmbracoApplicationStarting"/> notification
|
||||
/// </summary>
|
||||
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
|
||||
public void Handle(UmbracoApplicationStarting notification)
|
||||
{
|
||||
Install();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void Install()
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -47,7 +45,7 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
/// <summary>
|
||||
/// Handles the <see cref="UmbracoApplicationStarting"/> notification
|
||||
/// </summary>
|
||||
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
|
||||
public void Handle(UmbracoApplicationStarting notification)
|
||||
{
|
||||
// always setup the dashboard
|
||||
// note: UmbracoApiController instances are automatically registered
|
||||
@@ -57,14 +55,12 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
{
|
||||
FileService.SavingTemplate += FileService_SavingTemplate;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the <see cref="ServerVariablesParsing"/> notification
|
||||
/// </summary>
|
||||
public Task HandleAsync(ServerVariablesParsing notification, CancellationToken cancellationToken)
|
||||
public void Handle(ServerVariablesParsing notification)
|
||||
{
|
||||
IDictionary<string, object> serverVars = notification.ServerVariables;
|
||||
|
||||
@@ -96,8 +92,6 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
|
||||
umbracoUrls["modelsBuilderBaseUrl"] = _linkGenerator.GetUmbracoApiServiceBaseUrl<ModelsBuilderDashboardController>(controller => controller.BuildModels());
|
||||
umbracoPlugins["modelsBuilder"] = GetModelsBuilderSettings();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Dictionary<string, object> GetModelsBuilderSettings()
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
@@ -40,10 +38,9 @@ namespace Umbraco.ModelsBuilder.Embedded
|
||||
/// <summary>
|
||||
/// Handles the <see cref="UmbracoApplicationStarting"/> notification
|
||||
/// </summary>
|
||||
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
|
||||
public void Handle(UmbracoApplicationStarting notification)
|
||||
{
|
||||
Install();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void Install()
|
||||
|
||||
@@ -28,6 +28,22 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Events
|
||||
_builder = new UmbracoBuilder(register, Mock.Of<IConfiguration>(), TestHelper.GetMockedTypeLoader());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CanPublishAsyncEvents()
|
||||
{
|
||||
_builder.Services.AddScoped<Adder>();
|
||||
_builder.AddNotificationAsyncHandler<Notification, NotificationAsyncHandlerA>();
|
||||
_builder.AddNotificationAsyncHandler<Notification, NotificationAsyncHandlerB>();
|
||||
_builder.AddNotificationAsyncHandler<Notification, NotificationAsyncHandlerC>();
|
||||
ServiceProvider provider = _builder.Services.BuildServiceProvider();
|
||||
|
||||
var notification = new Notification();
|
||||
IEventAggregator aggregator = provider.GetService<IEventAggregator>();
|
||||
await aggregator.PublishAsync(notification);
|
||||
|
||||
Assert.AreEqual(A + B + C, notification.SubscriberCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CanPublishEvents()
|
||||
{
|
||||
@@ -51,19 +67,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Events
|
||||
|
||||
public class NotificationHandlerA : INotificationHandler<Notification>
|
||||
{
|
||||
public Task HandleAsync(Notification notification, CancellationToken cancellationToken)
|
||||
public void Handle(Notification notification)
|
||||
{
|
||||
notification.SubscriberCount += A;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public class NotificationHandlerB : INotificationHandler<Notification>
|
||||
{
|
||||
public Task HandleAsync(Notification notification, CancellationToken cancellationToken)
|
||||
public void Handle(Notification notification)
|
||||
{
|
||||
notification.SubscriberCount += B;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,13 +87,42 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Events
|
||||
|
||||
public NotificationHandlerC(Adder adder) => _adder = adder;
|
||||
|
||||
public void Handle(Notification notification)
|
||||
{
|
||||
notification.SubscriberCount = _adder.Add(notification.SubscriberCount, C);
|
||||
}
|
||||
}
|
||||
|
||||
public class NotificationAsyncHandlerA : INotificationAsyncHandler<Notification>
|
||||
{
|
||||
public Task HandleAsync(Notification notification, CancellationToken cancellationToken)
|
||||
{
|
||||
notification.SubscriberCount += A;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public class NotificationAsyncHandlerB : INotificationAsyncHandler<Notification>
|
||||
{
|
||||
public Task HandleAsync(Notification notification, CancellationToken cancellationToken)
|
||||
{
|
||||
notification.SubscriberCount += B;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public class NotificationAsyncHandlerC : INotificationAsyncHandler<Notification>
|
||||
{
|
||||
private readonly Adder _adder;
|
||||
|
||||
public NotificationAsyncHandlerC(Adder adder) => _adder = adder;
|
||||
|
||||
public Task HandleAsync(Notification notification, CancellationToken cancellationToken)
|
||||
{
|
||||
notification.SubscriberCount = _adder.Add(notification.SubscriberCount, C);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public class Adder
|
||||
{
|
||||
public int Add(int a, int b) => a + b;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -46,7 +44,7 @@ namespace Umbraco.Web.Common.Profiler
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken)
|
||||
public void Handle(UmbracoApplicationStarting notification)
|
||||
{
|
||||
if (_profile)
|
||||
{
|
||||
@@ -57,8 +55,6 @@ namespace Umbraco.Web.Common.Profiler
|
||||
// Stop the profiling of the booting process
|
||||
_profiler.StopBoot();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,7 +466,7 @@
|
||||
|
||||
syncTreeNode($scope.content, data.path, false, args.reloadChildren);
|
||||
|
||||
eventsService.emit("content.saved", { content: $scope.content, action: args.action });
|
||||
eventsService.emit("content.saved", { content: $scope.content, action: args.action, valid: true });
|
||||
|
||||
resetNestedFieldValiation(fieldsToRollback);
|
||||
ensureDirtyIsSetIfAnyVariantIsDirty();
|
||||
@@ -474,8 +474,15 @@
|
||||
return $q.when(data);
|
||||
},
|
||||
function (err) {
|
||||
|
||||
|
||||
syncTreeNode($scope.content, $scope.content.path);
|
||||
|
||||
if (err.status === 400 && err.data) {
|
||||
// content was saved but is invalid.
|
||||
eventsService.emit("content.saved", { content: $scope.content, action: args.action, valid: false });
|
||||
}
|
||||
|
||||
resetNestedFieldValiation(fieldsToRollback);
|
||||
|
||||
return $q.reject(err);
|
||||
@@ -981,7 +988,7 @@
|
||||
$scope.appChanged = function (activeApp) {
|
||||
|
||||
$scope.activeApp = activeApp;
|
||||
|
||||
|
||||
_.forEach($scope.content.apps, function (app) {
|
||||
app.active = false;
|
||||
if (app.alias === $scope.activeApp.alias) {
|
||||
|
||||
@@ -84,7 +84,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
//when true, the url will change but it won't actually re-route
|
||||
//this is merely here for compatibility, if only the content/media/members used this service we'd prob be ok but tons of editors
|
||||
//use this service unfortunately and probably packages too.
|
||||
args.softRedirect = false;
|
||||
args.softRedirect = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,13 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
self.handleSaveError({
|
||||
showNotifications: args.showNotifications,
|
||||
softRedirect: args.softRedirect,
|
||||
err: err
|
||||
err: err,
|
||||
rebindCallback: function () {
|
||||
// if the error contains data, we want to map that back as we want to continue editing this save. Especially important when the content is new as the returned data will contain ID etc.
|
||||
if(err.data) {
|
||||
rebindCallback.apply(self, [args.content, err.data]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//update editor state to what is current
|
||||
@@ -298,7 +304,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
}
|
||||
|
||||
// if publishing is allowed also allow schedule publish
|
||||
// we add this manually becuase it doesn't have a permission so it wont
|
||||
// we add this manually becuase it doesn't have a permission so it wont
|
||||
// get picked up by the loop through permissions
|
||||
if (_.contains(args.content.allowedActions, "U")) {
|
||||
buttons.subButtons.push(createButtonDefinition("SCHEDULE"));
|
||||
@@ -622,7 +628,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
if (!args.err) {
|
||||
throw "args.err cannot be null";
|
||||
}
|
||||
|
||||
|
||||
//When the status is a 400 status with a custom header: X-Status-Reason: Validation failed, we have validation errors.
|
||||
//Otherwise the error is probably due to invalid data (i.e. someone mucking around with the ids or something).
|
||||
//Or, some strange server error
|
||||
@@ -640,7 +646,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
|
||||
if (!this.redirectToCreatedContent(args.err.data.id, args.softRedirect) || args.softRedirect) {
|
||||
// If we are not redirecting it's because this is not newly created content, else in some cases we are
|
||||
// soft-redirecting which means the URL will change but the route wont (i.e. creating content).
|
||||
// soft-redirecting which means the URL will change but the route wont (i.e. creating content).
|
||||
|
||||
// In this case we need to detect what properties have changed and re-bind them with the server data.
|
||||
if (args.rebindCallback && angular.isFunction(args.rebindCallback)) {
|
||||
@@ -687,7 +693,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
if (!this.redirectToCreatedContent(args.redirectId ? args.redirectId : args.savedContent.id, args.softRedirect) || args.softRedirect) {
|
||||
|
||||
// If we are not redirecting it's because this is not newly created content, else in some cases we are
|
||||
// soft-redirecting which means the URL will change but the route wont (i.e. creating content).
|
||||
// soft-redirecting which means the URL will change but the route wont (i.e. creating content).
|
||||
|
||||
// In this case we need to detect what properties have changed and re-bind them with the server data.
|
||||
if (args.rebindCallback && angular.isFunction(args.rebindCallback)) {
|
||||
@@ -723,7 +729,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
navigationService.setSoftRedirect();
|
||||
}
|
||||
//change to new path
|
||||
$location.path("/" + $routeParams.section + "/" + $routeParams.tree + "/" + $routeParams.method + "/" + id);
|
||||
$location.path("/" + $routeParams.section + "/" + $routeParams.tree + "/" + $routeParams.method + "/" + id);
|
||||
//don't add a browser history for this
|
||||
$location.replace();
|
||||
return true;
|
||||
|
||||
@@ -104,19 +104,18 @@
|
||||
margin: 0 auto;
|
||||
list-style: none;
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.umb-card-grid li {
|
||||
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
width: 100px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.umb-card-grid.-six-in-row li {
|
||||
@@ -142,18 +141,20 @@
|
||||
.umb-card-grid .umb-card-grid-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
//height: 100%;
|
||||
padding-top: 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px 5px;
|
||||
border-radius: @baseBorderRadius * 2;
|
||||
transition: background-color 120ms;
|
||||
font-size: 13px;
|
||||
line-height: 1.3em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
> span {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
Reference in New Issue
Block a user