Merge remote-tracking branch 'origin/temp8' into temp8-3668-query-builder-snippits
This commit is contained in:
@@ -3,57 +3,57 @@
|
||||
[string]$Directory
|
||||
)
|
||||
$workingDirectory = $Directory
|
||||
CD $workingDirectory
|
||||
CD "$($workingDirectory)"
|
||||
|
||||
# Clone repo
|
||||
$fullGitUrl = "https://$env:GIT_URL/$env:GIT_REPOSITORYNAME.git"
|
||||
git clone $fullGitUrl 2>&1 | % { $_.ToString() }
|
||||
$fullGitUrl = "https://$($env:GIT_URL)/$($env:GIT_REPOSITORYNAME).git"
|
||||
git clone $($fullGitUrl) $($env:GIT_REPOSITORYNAME) 2>&1 | % { $_.ToString() }
|
||||
|
||||
# Remove everything so that unzipping the release later will update everything
|
||||
# Don't remove the readme file nor the git directory
|
||||
Write-Host "Cleaning up git directory before adding new version"
|
||||
Remove-Item -Recurse $workingDirectory\$env:GIT_REPOSITORYNAME\* -Exclude README.md,.git
|
||||
Remove-Item -Recurse "$($workingDirectory)\$($env:GIT_REPOSITORYNAME)\*" -Exclude README.md,.git
|
||||
|
||||
# Find release zip
|
||||
$zipsDir = "$workingDirectory\$env:BUILD_DEFINITIONNAME\zips"
|
||||
$zipsDir = "$($workingDirectory)\$($env:BUILD_DEFINITIONNAME)\zips"
|
||||
$pattern = "UmbracoCms.([0-9]{1,2}.[0-9]{1,3}.[0-9]{1,3}).zip"
|
||||
Write-Host "Searching for Umbraco release files in $workingDirectory\$zipsDir for a file with pattern $pattern"
|
||||
$file = (Get-ChildItem $zipsDir | Where-Object { $_.Name -match "$pattern" })
|
||||
Write-Host "Searching for Umbraco release files in $($zipsDir) for a file with pattern $($pattern)"
|
||||
$file = (Get-ChildItem "$($zipsDir)" | Where-Object { $_.Name -match "$($pattern)" })
|
||||
|
||||
if($file)
|
||||
{
|
||||
# Get release name
|
||||
$version = [regex]::Match($file.Name, $pattern).captures.groups[1].value
|
||||
$releaseName = "Umbraco $version"
|
||||
Write-Host "Found $releaseName"
|
||||
$version = [regex]::Match($($file.Name), $($pattern)).captures.groups[1].value
|
||||
$releaseName = "Umbraco $($version)"
|
||||
Write-Host "Found $($releaseName)"
|
||||
|
||||
# Unzip into repository to update release
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
Write-Host "Unzipping $($file.FullName) to $workingDirectory\$env:GIT_REPOSITORYNAME"
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory("$($file.FullName)", "$workingDirectory\$env:GIT_REPOSITORYNAME")
|
||||
Write-Host "Unzipping $($file.FullName) to $($workingDirectory)\$($env:GIT_REPOSITORYNAME)"
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory("$($file.FullName)", "$($workingDirectory)\$($env:GIT_REPOSITORYNAME)")
|
||||
|
||||
# Telling git who we are
|
||||
git config --global user.email "coffee@umbraco.com" 2>&1 | % { $_.ToString() }
|
||||
git config --global user.name "Umbraco HQ" 2>&1 | % { $_.ToString() }
|
||||
|
||||
# Commit
|
||||
CD $env:GIT_REPOSITORYNAME
|
||||
Write-Host "Committing Umbraco $version Release from Build Output"
|
||||
CD "$($workingDirectory)\$($env:GIT_REPOSITORYNAME)"
|
||||
Write-Host "Committing Umbraco $($version) Release from Build Output"
|
||||
|
||||
git add . 2>&1 | % { $_.ToString() }
|
||||
git commit -m " Release $releaseName from Build Output" 2>&1 | % { $_.ToString() }
|
||||
git commit -m " Release $($releaseName) from Build Output" 2>&1 | % { $_.ToString() }
|
||||
|
||||
# Tag the release
|
||||
git tag -a "v$version" -m "v$version"
|
||||
git tag -a "v$($version)" -m "v$($version)"
|
||||
|
||||
# Push release to master
|
||||
$fullGitAuthUrl = "https://$($env:GIT_USERNAME):$GitHubPersonalAccessToken@$env:GIT_URL/$env:GIT_REPOSITORYNAME.git"
|
||||
git push $fullGitAuthUrl 2>&1 | % { $_.ToString() }
|
||||
$fullGitAuthUrl = "https://$($env:GIT_USERNAME):$($GitHubPersonalAccessToken)@$($env:GIT_URL)/$($env:GIT_REPOSITORYNAME).git"
|
||||
git push $($fullGitAuthUrl) 2>&1 | % { $_.ToString() }
|
||||
|
||||
#Push tag to master
|
||||
git push $fullGitAuthUrl --tags 2>&1 | % { $_.ToString() }
|
||||
git push $($fullGitAuthUrl) --tags 2>&1 | % { $_.ToString() }
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Error "Umbraco release file not found, searched in $workingDirectory\$zipsDir for a file with pattern $pattern - cancelling"
|
||||
Write-Error "Umbraco release file not found, searched in $($workingDirectory)\$($zipsDir) for a file with pattern $($pattern) - canceling"
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<dependency id="ClientDependency" version="[1.9.7,1.999999)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
|
||||
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
|
||||
<dependency id="Examine" version="[1.0.0-beta072,1.999999)" />
|
||||
<dependency id="Examine" version="[1.0.0-beta078,1.999999)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.8.9,1.999999)" />
|
||||
<dependency id="ImageProcessor" version="[2.6.2.25,2.999999)" />
|
||||
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
not want this to happen as the alpha of the next major is, really, the next major already.
|
||||
-->
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3, 2.999999)" />
|
||||
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.31]" />
|
||||
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.33]" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.9.3.25,4.999999)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.4.1.19,2.999999)" />
|
||||
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[2.0.1,2.999999)" />
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Components
|
||||
public class Composition : IRegister
|
||||
{
|
||||
private readonly Dictionary<Type, ICollectionBuilder> _builders = new Dictionary<Type, ICollectionBuilder>();
|
||||
private readonly Dictionary<Type, Unique> _uniques = new Dictionary<Type, Unique>();
|
||||
private readonly Dictionary<string, Action<IRegister>> _uniques = new Dictionary<string, Action<IRegister>>();
|
||||
private readonly IRegister _register;
|
||||
|
||||
/// <summary>
|
||||
@@ -83,11 +83,32 @@ namespace Umbraco.Core.Components
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Register<TService>(Func<IFactory, TService> factory, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
=> _register.Register(factory, lifetime);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterInstance(Type serviceType, object instance)
|
||||
=> _register.RegisterInstance(serviceType, instance);
|
||||
public void Register(Type serviceType, object instance)
|
||||
=> _register.Register(serviceType, instance);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterFor<TService, TTarget>(Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
=> _register.RegisterFor<TService, TTarget>(lifetime);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterFor<TService, TTarget>(Type implementingType, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
=> _register.RegisterFor<TService, TTarget>(implementingType, lifetime);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterFor<TService, TTarget>(Func<IFactory, TService> factory, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
=> _register.RegisterFor<TService, TTarget>(factory, lifetime);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterFor<TService, TTarget>(TService instance)
|
||||
where TService : class
|
||||
=> _register.RegisterFor<TService, TTarget>(instance);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterAuto(Type serviceBaseType)
|
||||
@@ -104,10 +125,12 @@ namespace Umbraco.Core.Components
|
||||
onCreating();
|
||||
|
||||
foreach (var unique in _uniques.Values)
|
||||
unique.RegisterWith(_register);
|
||||
unique(_register);
|
||||
_uniques.Clear(); // no point keep them around
|
||||
|
||||
foreach (var builder in _builders.Values)
|
||||
builder.RegisterWith(_register);
|
||||
_builders.Clear(); // no point keep them around
|
||||
|
||||
Configs.RegisterWith(_register);
|
||||
|
||||
@@ -123,74 +146,78 @@ namespace Umbraco.Core.Components
|
||||
|
||||
#region Unique
|
||||
|
||||
private string GetUniqueName<TService>()
|
||||
=> GetUniqueName(typeof(TService));
|
||||
|
||||
private string GetUniqueName(Type serviceType)
|
||||
=> serviceType.FullName;
|
||||
|
||||
private string GetUniqueName<TService, TTarget>()
|
||||
=> GetUniqueName(typeof(TService), typeof(TTarget));
|
||||
|
||||
private string GetUniqueName(Type serviceType, Type targetType)
|
||||
=> serviceType.FullName + "::" + targetType.FullName;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service.
|
||||
/// Registers a unique service as its own implementation.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUnique(Type serviceType)
|
||||
=> _uniques[GetUniqueName(serviceType)] = register => register.Register(serviceType, Lifetime.Singleton);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service with an implementation type.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUnique(Type serviceType, Type implementingType)
|
||||
=> _uniques[serviceType] = new Unique(serviceType, implementingType);
|
||||
=> _uniques[GetUniqueName(serviceType)] = register => register.Register(serviceType, implementingType, Lifetime.Singleton);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUnique(Type serviceType, object instance)
|
||||
=> _uniques[serviceType] = new Unique(serviceType, instance);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service.
|
||||
/// Registers a unique service with an implementation factory.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUnique<TService>(Func<IFactory, TService> factory)
|
||||
=> _uniques[typeof(TService)] = new Unique<TService>(factory);
|
||||
where TService : class
|
||||
=> _uniques[GetUniqueName<TService>()] = register => register.Register<TService>(factory, Lifetime.Singleton);
|
||||
|
||||
private class Unique
|
||||
{
|
||||
private readonly Type _serviceType;
|
||||
private readonly Type _implementingType;
|
||||
private readonly object _instance;
|
||||
/// <summary>
|
||||
/// Registers a unique service with an implementing instance.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUnique(Type serviceType, object instance)
|
||||
=> _uniques[GetUniqueName(serviceType)] = register => register.Register(serviceType, instance);
|
||||
|
||||
protected Unique(Type serviceType)
|
||||
{
|
||||
_serviceType = serviceType;
|
||||
}
|
||||
/// <summary>
|
||||
/// Registers a unique service for a target, as its own implementation.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUniqueFor<TService, TTarget>()
|
||||
where TService : class
|
||||
=> _uniques[GetUniqueName<TService, TTarget>()] = register => register.RegisterFor<TService, TTarget>(Lifetime.Singleton);
|
||||
|
||||
public Unique(Type serviceType, Type implementingType)
|
||||
: this(serviceType)
|
||||
{
|
||||
_implementingType = implementingType;
|
||||
}
|
||||
/// <summary>
|
||||
/// Registers a unique service for a target, with an implementing type.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUniqueFor<TService, TTarget>(Type implementingType)
|
||||
where TService : class
|
||||
=> _uniques[GetUniqueName<TService, TTarget>()] = register => register.RegisterFor<TService, TTarget>(implementingType, Lifetime.Singleton);
|
||||
|
||||
public Unique(Type serviceType, object instance)
|
||||
: this(serviceType)
|
||||
{
|
||||
_instance = instance;
|
||||
}
|
||||
/// <summary>
|
||||
/// Registers a unique service for a target, with an implementation factory.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUniqueFor<TService, TTarget>(Func<IFactory, TService> factory)
|
||||
where TService : class
|
||||
=> _uniques[GetUniqueName<TService, TTarget>()] = register => register.RegisterFor<TService, TTarget>(factory, Lifetime.Singleton);
|
||||
|
||||
public virtual void RegisterWith(IRegister register)
|
||||
{
|
||||
if (_implementingType != null)
|
||||
register.Register(_serviceType, _implementingType, Lifetime.Singleton);
|
||||
else if (_instance != null)
|
||||
register.RegisterInstance(_serviceType, _instance);
|
||||
}
|
||||
}
|
||||
|
||||
private class Unique<TService> : Unique
|
||||
{
|
||||
private readonly Func<IFactory, TService> _factory;
|
||||
|
||||
public Unique(Func<IFactory, TService> factory)
|
||||
: base(typeof(TService))
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public override void RegisterWith(IRegister register)
|
||||
{
|
||||
register.Register(_factory, Lifetime.Singleton);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Registers a unique service for a target, with an implementing instance.
|
||||
/// </summary>
|
||||
/// <remarks>Unique services have one single implementation, and a Singleton lifetime.</remarks>
|
||||
public void RegisterUniqueFor<TService, TTarget>(TService instance)
|
||||
where TService : class
|
||||
=> _uniques[GetUniqueName<TService, TTarget>()] = register => register.RegisterFor<TService, TTarget>(instance);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -26,15 +26,16 @@ namespace Umbraco.Core.Components
|
||||
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
|
||||
/// <typeparam name="TImplementing">The implementing type.</typeparam>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="supportingFileSystemFactory">A factory method creating the supporting filesystem.</param>
|
||||
/// <returns>The register.</returns>
|
||||
public static void RegisterFileSystem<TFileSystem, TImplementing>(this Composition composition, Func<IFactory, IFileSystem> supportingFileSystemFactory)
|
||||
public static void RegisterFileSystem<TFileSystem, TImplementing>(this Composition composition)
|
||||
where TImplementing : FileSystemWrapper, TFileSystem
|
||||
where TFileSystem : class
|
||||
{
|
||||
composition.RegisterUnique<TFileSystem>(factory =>
|
||||
{
|
||||
var fileSystems = factory.GetInstance<FileSystems>();
|
||||
return fileSystems.GetFileSystem<TImplementing>(supportingFileSystemFactory(factory));
|
||||
var supporting = factory.GetInstance<SupportingFileSystems>();
|
||||
return fileSystems.GetFileSystem<TImplementing>(supporting.For<TFileSystem>());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,15 +44,15 @@ namespace Umbraco.Core.Components
|
||||
/// </summary>
|
||||
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="supportingFileSystemFactory">A factory method creating the supporting filesystem.</param>
|
||||
/// <returns>The register.</returns>
|
||||
public static void RegisterFileSystem<TFileSystem>(this Composition composition, Func<IFactory, IFileSystem> supportingFileSystemFactory)
|
||||
public static void RegisterFileSystem<TFileSystem>(this Composition composition)
|
||||
where TFileSystem : FileSystemWrapper
|
||||
{
|
||||
composition.RegisterUnique(factory =>
|
||||
{
|
||||
var fileSystems = factory.GetInstance<FileSystems>();
|
||||
return fileSystems.GetFileSystem<TFileSystem>(supportingFileSystemFactory(factory));
|
||||
var supporting = factory.GetInstance<SupportingFileSystems>();
|
||||
return fileSystems.GetFileSystem<TFileSystem>(supporting.For<TFileSystem>());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -280,6 +281,22 @@ namespace Umbraco.Core.Components
|
||||
composition.RegisterUnique(_ => helper);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the underlying media filesystem.
|
||||
/// </summary>
|
||||
/// <param name="composition">A composition.</param>
|
||||
/// <param name="filesystemFactory">A filesystem factory.</param>
|
||||
public static void SetMediaFileSystem(this Composition composition, Func<IFactory, IFileSystem> filesystemFactory)
|
||||
=> composition.RegisterUniqueFor<IFileSystem, IMediaFileSystem>(filesystemFactory);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the underlying media filesystem.
|
||||
/// </summary>
|
||||
/// <param name="composition">A composition.</param>
|
||||
/// <param name="filesystemFactory">A filesystem factory.</param>
|
||||
public static void SetMediaFileSystem(this Composition composition, Func<IFileSystem> filesystemFactory)
|
||||
=> composition.RegisterUniqueFor<IFileSystem, IMediaFileSystem>(_ => filesystemFactory());
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
public abstract class CollectionBuilderBase<TBuilder, TCollection, TItem> : ICollectionBuilder<TCollection, TItem>
|
||||
where TBuilder: CollectionBuilderBase<TBuilder, TCollection, TItem>
|
||||
where TCollection : IBuilderCollection<TItem>
|
||||
where TCollection : class, IBuilderCollection<TItem>
|
||||
{
|
||||
private readonly List<Type> _types = new List<Type>();
|
||||
private readonly object _locker = new object();
|
||||
|
||||
@@ -12,10 +12,9 @@ namespace Umbraco.Core.Composing.Composers
|
||||
*
|
||||
* Create a component and use it to modify the composition by adding something like:
|
||||
*
|
||||
* composition.Container.RegisterFileSystem<IMediaFileSystem, MediaFileSystem>(
|
||||
* factory => new PhysicalFileSystem("~/somewhere"));
|
||||
* composition.RegisterUniqueFor<IFileSystem, IMediaFileSystem>(...);
|
||||
*
|
||||
* return whatever supporting filesystem you like.
|
||||
* and register whatever supporting filesystem you like.
|
||||
*
|
||||
*
|
||||
* HOW TO IMPLEMENT MY OWN FILESYSTEM
|
||||
@@ -30,12 +29,15 @@ namespace Umbraco.Core.Composing.Composers
|
||||
* { }
|
||||
* }
|
||||
*
|
||||
* The ctor can have more parameters that will be resolved by the container.
|
||||
* The ctor can have more parameters, that will be resolved by the container.
|
||||
*
|
||||
* Register your filesystem, in a component:
|
||||
*
|
||||
* composition.Container.RegisterFileSystem<MyFileSystem>(
|
||||
* factory => new PhysicalFileSystem("~/my"));
|
||||
* composition.RegisterFileSystem<MyFileSystem>();
|
||||
*
|
||||
* Register the underlying filesystem:
|
||||
*
|
||||
* composition.RegisterUniqueFor<IFileSystem, MyFileSystem>(...);
|
||||
*
|
||||
* And that's it, you can inject MyFileSystem wherever it's needed.
|
||||
*
|
||||
@@ -48,8 +50,8 @@ namespace Umbraco.Core.Composing.Composers
|
||||
* Make the class implement the interface, then
|
||||
* register your filesystem, in a component:
|
||||
*
|
||||
* composition.Container.RegisterFileSystem<IMyFileSystem, MyFileSystem>(
|
||||
* factory => new PhysicalFileSystem("~/my"));
|
||||
* composition.RegisterFileSystem<IMyFileSystem, MyFileSystem>();
|
||||
* composition.RegisterUniqueFor<IFileSystem, IMyFileSystem>(...);
|
||||
*
|
||||
* And that's it, you can inject IMyFileSystem wherever it's needed.
|
||||
*
|
||||
@@ -79,9 +81,16 @@ namespace Umbraco.Core.Composing.Composers
|
||||
// register the scheme for media paths
|
||||
composition.RegisterUnique<IMediaPathScheme, TwoGuidsMediaPathScheme>();
|
||||
|
||||
// register the IMediaFileSystem implementation with a supporting filesystem
|
||||
composition.RegisterFileSystem<IMediaFileSystem, MediaFileSystem>(
|
||||
factory => new PhysicalFileSystem("~/media"));
|
||||
// register the IMediaFileSystem implementation
|
||||
composition.RegisterFileSystem<IMediaFileSystem, MediaFileSystem>();
|
||||
|
||||
// register the supporting filesystems provider
|
||||
composition.Register(factory => new SupportingFileSystems(factory), Lifetime.Singleton);
|
||||
|
||||
// register the IFileSystem supporting the IMediaFileSystem
|
||||
// THIS IS THE ONLY THING THAT NEEDS TO CHANGE, IN ORDER TO REPLACE THE UNDERLYING FILESYSTEM
|
||||
// and, SupportingFileSystem.For<IMediaFileSystem>() returns the underlying filesystem
|
||||
composition.SetMediaFileSystem(() => new PhysicalFileSystem("~/media"));
|
||||
|
||||
return composition;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,13 @@ namespace Umbraco.Core.Composing
|
||||
public static void RegisterUnique<TService, TImplementing>(this Composition composition)
|
||||
=> composition.RegisterUnique(typeof(TService), typeof(TImplementing));
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service with an implementation type, for a target.
|
||||
/// </summary>
|
||||
public static void RegisterUniqueFor<TService, TTarget, TImplementing>(this Composition composition)
|
||||
where TService : class
|
||||
=> composition.RegisterUniqueFor<TService, TTarget>(typeof(TImplementing));
|
||||
|
||||
/// <summary>
|
||||
/// Registers a unique service with an implementing instance.
|
||||
/// </summary>
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <returns>An instance of the specified type.</returns>
|
||||
/// <remarks>Throws an exception if the factory failed to get an instance of the specified type.</remarks>
|
||||
public static T GetInstance<T>(this IFactory factory)
|
||||
where T : class
|
||||
=> (T)factory.GetInstance(typeof(T));
|
||||
|
||||
/// <summary>
|
||||
@@ -28,6 +29,7 @@ namespace Umbraco.Core.Composing
|
||||
/// of the specified type. Throws an exception if the factory does know how
|
||||
/// to get an instance of the specified type, but failed to do so.</remarks>
|
||||
public static T TryGetInstance<T>(this IFactory factory)
|
||||
where T : class
|
||||
=> (T)factory.TryGetInstance(typeof(T));
|
||||
|
||||
/// <summary>
|
||||
@@ -42,6 +44,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <para>The arguments are used as dependencies by the factory.</para>
|
||||
/// </remarks>
|
||||
public static T CreateInstance<T>(this IFactory factory, params object[] args)
|
||||
where T : class
|
||||
=> (T)factory.CreateInstance(typeof(T), args);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -3,13 +3,6 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
// Implementing:
|
||||
//
|
||||
// The factory
|
||||
// - always picks the constructor with the most parameters
|
||||
// - supports Lazy parameters (and prefers them over non-Lazy) in constructors
|
||||
// - what happens with 'releasing' is unclear
|
||||
|
||||
/// <summary>
|
||||
/// Defines a service factory for Umbraco.
|
||||
/// </summary>
|
||||
@@ -28,6 +21,15 @@ namespace Umbraco.Core.Composing
|
||||
/// <remarks>Throws an exception if the container failed to get an instance of the specified type.</remarks>
|
||||
object GetInstance(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a targeted instance of a service.
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">The type of the service.</typeparam>
|
||||
/// <typeparam name="TTarget">The type of the target.</typeparam>
|
||||
/// <returns>The instance of the specified type for the specified target.</returns>
|
||||
/// <remarks>Throws an exception if the container failed to get an instance of the specified type.</remarks>
|
||||
TService GetInstanceFor<TService, TTarget>();
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get an instance of a service.
|
||||
/// </summary>
|
||||
@@ -48,7 +50,8 @@ namespace Umbraco.Core.Composing
|
||||
/// Gets all instances of a service.
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">The type of the service.</typeparam>
|
||||
IEnumerable<TService> GetAllInstances<TService>();
|
||||
IEnumerable<TService> GetAllInstances<TService>()
|
||||
where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// Releases an instance.
|
||||
|
||||
@@ -2,17 +2,6 @@
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
// Implementing:
|
||||
//
|
||||
// The register
|
||||
// - supports registering a service, even after some instances of other services have been created
|
||||
// - supports re-registering a service, as long as no instance of that service has been created
|
||||
// - throws when re-registering a service, and an instance of that service has been created
|
||||
//
|
||||
// - registers only one implementation of a nameless service, re-registering replaces the previous
|
||||
// registration - names are required to register multiple implementations - and getting an
|
||||
// IEnumerable of the service, nameless, returns them all
|
||||
|
||||
/// <summary>
|
||||
/// Defines a service register for Umbraco.
|
||||
/// </summary>
|
||||
@@ -36,12 +25,53 @@ namespace Umbraco.Core.Composing
|
||||
/// <summary>
|
||||
/// Registers a service with an implementation factory.
|
||||
/// </summary>
|
||||
void Register<TService>(Func<IFactory, TService> factory, Lifetime lifetime = Lifetime.Transient);
|
||||
void Register<TService>(Func<IFactory, TService> factory, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service with an implementing instance.
|
||||
/// </summary>
|
||||
void RegisterInstance(Type serviceType, object instance);
|
||||
void Register(Type serviceType, object instance);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service for a target, as its own implementation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There can only be one implementation or instanced registered for a service and target;
|
||||
/// what happens if many are registered is not specified.
|
||||
/// </remarks>
|
||||
void RegisterFor<TService, TTarget>(Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service for a target, with an implementation type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There can only be one implementation or instanced registered for a service and target;
|
||||
/// what happens if many are registered is not specified.
|
||||
/// </remarks>
|
||||
void RegisterFor<TService, TTarget>(Type implementingType, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service for a target, with an implementation factory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There can only be one implementation or instanced registered for a service and target;
|
||||
/// what happens if many are registered is not specified.
|
||||
/// </remarks>
|
||||
void RegisterFor<TService, TTarget>(Func<IFactory, TService> factory, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service for a target, with an implementing instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There can only be one implementation or instanced registered for a service and target;
|
||||
/// what happens if many are registered is not specified.
|
||||
/// </remarks>
|
||||
void RegisterFor<TService, TTarget>(TService instance)
|
||||
where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a base type for auto-registration.
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
public abstract class LazyCollectionBuilderBase<TBuilder, TCollection, TItem> : CollectionBuilderBase<TBuilder, TCollection, TItem>
|
||||
where TBuilder : LazyCollectionBuilderBase<TBuilder, TCollection, TItem>
|
||||
where TCollection : IBuilderCollection<TItem>
|
||||
where TCollection : class, IBuilderCollection<TItem>
|
||||
{
|
||||
private readonly List<Func<IEnumerable<Type>>> _producers = new List<Func<IEnumerable<Type>>>();
|
||||
private readonly List<Type> _excluded = new List<Type>();
|
||||
|
||||
@@ -102,18 +102,25 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
/// <inheritdoc />
|
||||
public IFactory CreateFactory() => this;
|
||||
|
||||
private static string GetTargetedServiceName<TTarget>() => "TARGET:" + typeof(TTarget).FullName;
|
||||
|
||||
#region Factory
|
||||
|
||||
/// <inheritdoc />
|
||||
public object GetInstance(Type type)
|
||||
=> Container.GetInstance(type);
|
||||
|
||||
/// <inheritdoc />
|
||||
public TService GetInstanceFor<TService, TTarget>()
|
||||
=> Container.GetInstance<TService>(GetTargetedServiceName<TTarget>());
|
||||
|
||||
/// <inheritdoc />
|
||||
public object TryGetInstance(Type type)
|
||||
=> Container.TryGetInstance(type);
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<T> GetAllInstances<T>()
|
||||
where T : class
|
||||
=> Container.GetAllInstances<T>();
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -138,21 +145,7 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Register(Type serviceType, Lifetime lifetime = Lifetime.Transient)
|
||||
{
|
||||
switch (lifetime)
|
||||
{
|
||||
case Lifetime.Transient:
|
||||
Container.Register(serviceType);
|
||||
break;
|
||||
case Lifetime.Request:
|
||||
case Lifetime.Scope:
|
||||
case Lifetime.Singleton:
|
||||
Container.Register(serviceType, GetLifetime(lifetime));
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"Lifetime {lifetime} is not supported.");
|
||||
}
|
||||
}
|
||||
=> Container.Register(serviceType, GetLifetime(lifetime));
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Register(Type serviceType, Type implementingType, Lifetime lifetime = Lifetime.Transient)
|
||||
@@ -174,22 +167,41 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Register<TService>(Func<IFactory, TService> factory, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
{
|
||||
switch (lifetime)
|
||||
{
|
||||
case Lifetime.Transient:
|
||||
Container.Register(f => factory(this));
|
||||
break;
|
||||
case Lifetime.Request:
|
||||
case Lifetime.Scope:
|
||||
case Lifetime.Singleton:
|
||||
Container.Register(f => factory(this), GetLifetime(lifetime));
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"Lifetime {lifetime} is not supported.");
|
||||
}
|
||||
Container.Register(f => factory(this), GetLifetime(lifetime));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Register(Type serviceType, object instance)
|
||||
=> Container.RegisterInstance(serviceType, instance);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterFor<TService, TTarget>(Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
=> RegisterFor<TService, TTarget>(typeof(TService), lifetime);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterFor<TService, TTarget>(Type implementingType, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
{
|
||||
// note that there can only be one implementation or instance registered "for" a service
|
||||
Container.Register(typeof(TService), implementingType, GetTargetedServiceName<TTarget>(), GetLifetime(lifetime));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterFor<TService, TTarget>(Func<IFactory, TService> factory, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
{
|
||||
// note that there can only be one implementation or instance registered "for" a service
|
||||
Container.Register(f => factory(this), GetTargetedServiceName<TTarget>(), GetLifetime(lifetime));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterFor<TService, TTarget>(TService instance)
|
||||
where TService : class
|
||||
=> Container.RegisterInstance(typeof(TService), instance, GetTargetedServiceName<TTarget>());
|
||||
|
||||
private ILifetime GetLifetime(Lifetime lifetime)
|
||||
{
|
||||
switch (lifetime)
|
||||
@@ -207,10 +219,6 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterInstance(Type serviceType, object instance)
|
||||
=> Container.RegisterInstance(serviceType, instance);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterAuto(Type serviceBaseType)
|
||||
{
|
||||
@@ -223,17 +231,6 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
}, null);
|
||||
}
|
||||
|
||||
// was the Light-Inject specific way of dealing with args, but we've replaced it with our own
|
||||
// beware! does NOT work on singletons, see https://github.com/seesharper/LightInject/issues/294
|
||||
//
|
||||
///// <inheritdoc />
|
||||
//public void RegisterConstructorDependency<TDependency>(Func<IContainer, ParameterInfo, TDependency> factory)
|
||||
// => Container.RegisterConstructorDependency((f, x) => factory(this, x));
|
||||
//
|
||||
///// <inheritdoc />
|
||||
//public void RegisterConstructorDependency<TDependency>(Func<IContainer, ParameterInfo, object[], TDependency> factory)
|
||||
// => Container.RegisterConstructorDependency((f, x, a) => factory(this, x, a));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Control
|
||||
@@ -256,21 +253,14 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
|
||||
private class AssemblyScanner : IAssemblyScanner
|
||||
{
|
||||
//private readonly IAssemblyScanner _scanner;
|
||||
|
||||
//public AssemblyScanner(IAssemblyScanner scanner)
|
||||
//{
|
||||
// _scanner = scanner;
|
||||
//}
|
||||
|
||||
public void Scan(Assembly assembly, IServiceRegistry serviceRegistry, Func<ILifetime> lifetime, Func<Type, Type, bool> shouldRegister, Func<Type, Type, string> serviceNameProvider)
|
||||
{
|
||||
// nothing - we *could* scan non-Umbraco assemblies, though
|
||||
// nothing - we don't want LightInject to scan
|
||||
}
|
||||
|
||||
public void Scan(Assembly assembly, IServiceRegistry serviceRegistry)
|
||||
{
|
||||
// nothing - we *could* scan non-Umbraco assemblies, though
|
||||
// nothing - we don't want LightInject to scan
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
// of PerWebRequestScopeManagerProvider - but all delegates see is the mixed one - and therefore
|
||||
// they can transition without issues.
|
||||
//
|
||||
// The PerWebRequestScopeManager maintains the scope in HttpContext and LightInject registers a
|
||||
// module (PreApplicationStartMethod) which disposes it on EndRequest
|
||||
//
|
||||
// the mixed provider is installed in container.ConfigureUmbracoCore() and then,
|
||||
// when doing eg container.EnableMvc() or anything that does container.EnablePerWebRequestScope()
|
||||
// we need to take great care to preserve the mixed scope manager provider!
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
public abstract class OrderedCollectionBuilderBase<TBuilder, TCollection, TItem> : CollectionBuilderBase<TBuilder, TCollection, TItem>
|
||||
where TBuilder : OrderedCollectionBuilderBase<TBuilder, TCollection, TItem>
|
||||
where TCollection : IBuilderCollection<TItem>
|
||||
where TCollection : class, IBuilderCollection<TItem>
|
||||
{
|
||||
protected abstract TBuilder This { get; }
|
||||
|
||||
|
||||
@@ -11,22 +11,32 @@
|
||||
public static void Register<TService, TImplementing>(this IRegister register, Lifetime lifetime = Lifetime.Transient)
|
||||
=> register.Register(typeof(TService), typeof(TImplementing), lifetime);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service with an implementation type, for a target.
|
||||
/// </summary>
|
||||
public static void RegisterFor<TService, TImplementing, TTarget>(this IRegister register, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
=> register.RegisterFor<TService, TTarget>(typeof(TImplementing), lifetime);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service as its own implementation.
|
||||
/// </summary>
|
||||
public static void Register<TService>(this IRegister register, Lifetime lifetime = Lifetime.Transient)
|
||||
where TService : class
|
||||
=> register.Register(typeof(TService), lifetime);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a service with an implementing instance.
|
||||
/// </summary>
|
||||
public static void RegisterInstance<TService>(this IRegister register, TService instance)
|
||||
=> register.RegisterInstance(typeof(TService), instance);
|
||||
public static void Register<TService>(this IRegister register, TService instance)
|
||||
where TService : class
|
||||
=> register.Register(typeof(TService), instance);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a base type for auto-registration.
|
||||
/// </summary>
|
||||
public static void RegisterAuto<TServiceBase>(this IRegister register)
|
||||
where TServiceBase : class
|
||||
=> register.RegisterAuto(typeof(TServiceBase));
|
||||
}
|
||||
}
|
||||
|
||||
18
src/Umbraco.Core/Composing/TargetedServiceFactory.cs
Normal file
18
src/Umbraco.Core/Composing/TargetedServiceFactory.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for targeted service factories.
|
||||
/// </summary>
|
||||
/// <typeparam name="TService"></typeparam>
|
||||
public abstract class TargetedServiceFactory<TService>
|
||||
{
|
||||
private readonly IFactory _factory;
|
||||
|
||||
protected TargetedServiceFactory(IFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
public TService For<TTarget>() => _factory.GetInstanceFor<TService, TTarget>();
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Composing
|
||||
/// <typeparam name="TItem">The type of the items.</typeparam>
|
||||
public abstract class WeightedCollectionBuilderBase<TBuilder, TCollection, TItem> : CollectionBuilderBase<TBuilder, TCollection, TItem>
|
||||
where TBuilder : WeightedCollectionBuilderBase<TBuilder, TCollection, TItem>
|
||||
where TCollection : IBuilderCollection<TItem>
|
||||
where TCollection : class, IBuilderCollection<TItem>
|
||||
{
|
||||
protected abstract TBuilder This { get; }
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Umbraco.Core.Configuration
|
||||
if (_registerings == null)
|
||||
throw new InvalidOperationException("Configurations have already been registered.");
|
||||
|
||||
register.RegisterInstance(this);
|
||||
register.Register(this);
|
||||
|
||||
foreach (var registering in _registerings.Values)
|
||||
registering(register);
|
||||
|
||||
@@ -17,19 +17,19 @@ namespace Umbraco.Core.Deploy
|
||||
IEnumerable<string> PropertyEditorAliases { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the deploy property corresponding to a content property.
|
||||
/// Gets the deploy property value corresponding to a content property value, and gather dependencies.
|
||||
/// </summary>
|
||||
/// <param name="property">The content property.</param>
|
||||
/// <param name="value">The content property value.</param>
|
||||
/// <param name="dependencies">The content dependencies.</param>
|
||||
/// <returns>The deploy property value.</returns>
|
||||
string GetValue(Property property, ICollection<ArtifactDependency> dependencies);
|
||||
string ToArtifact(object value, ICollection<ArtifactDependency> dependencies);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a content property value using a deploy property.
|
||||
/// Gets the content property value corresponding to a deploy property value.
|
||||
/// </summary>
|
||||
/// <param name="content">The content item.</param>
|
||||
/// <param name="alias">The property alias.</param>
|
||||
/// <param name="value">The deploy property value.</param>
|
||||
void SetValue(IContentBase content, string alias, string value);
|
||||
/// <param name="currentValue">The current content property value.</param>
|
||||
/// <returns>The content property value.</returns>
|
||||
object FromArtifact(string value, object currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
11
src/Umbraco.Core/IO/SupportingFileSystems.cs
Normal file
11
src/Umbraco.Core/IO/SupportingFileSystems.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
public class SupportingFileSystems : TargetedServiceFactory<IFileSystem>
|
||||
{
|
||||
public SupportingFileSystems(IFactory factory)
|
||||
: base(factory)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -121,6 +121,8 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<DropTaskTables>("{648A2D5F-7467-48F8-B309-E99CEEE00E2A}"); // fixed version
|
||||
To<MakeTagsVariant>("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}");
|
||||
To<MakeRedirectUrlVariant>("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}");
|
||||
To<AddContentTypeIsElementColumn>("{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}");
|
||||
|
||||
|
||||
//FINAL
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
public class AddContentTypeIsElementColumn : MigrationBase
|
||||
{
|
||||
public AddContentTypeIsElementColumn(IMigrationContext context) : base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
AddColumn<ContentTypeDto>("isElement");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ namespace Umbraco.Core.Models
|
||||
private string _thumbnail = "folder.png";
|
||||
private bool _allowedAsRoot; // note: only one that's not 'pure element type'
|
||||
private bool _isContainer;
|
||||
private bool _isElement;
|
||||
private PropertyGroupCollection _propertyGroups;
|
||||
private PropertyTypeCollection _noGroupPropertyTypes;
|
||||
private IEnumerable<ContentTypeSort> _allowedContentTypes;
|
||||
@@ -90,6 +91,7 @@ namespace Umbraco.Core.Models
|
||||
public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Icon);
|
||||
public readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Thumbnail);
|
||||
public readonly PropertyInfo AllowedAsRootSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.AllowedAsRoot);
|
||||
public readonly PropertyInfo IsElementSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.IsElement);
|
||||
public readonly PropertyInfo IsContainerSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.IsContainer);
|
||||
public readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<ContentTypeSort>>(x => x.AllowedContentTypes);
|
||||
public readonly PropertyInfo PropertyGroupsSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, PropertyGroupCollection>(x => x.PropertyGroups);
|
||||
@@ -180,6 +182,14 @@ namespace Umbraco.Core.Models
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _isContainer, Ps.Value.IsContainerSelector);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DataMember]
|
||||
public bool IsElement
|
||||
{
|
||||
get => _isElement;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _isElement, Ps.Value.IsElementSelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of integer Ids for allowed ContentTypes
|
||||
/// </summary>
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
var type = contentType.GetType();
|
||||
var itemType = PublishedItemType.Unknown;
|
||||
if (typeof(IContentType).IsAssignableFrom(type)) itemType = PublishedItemType.Content;
|
||||
if (contentType.IsElement) itemType = PublishedItemType.Element;
|
||||
else if (typeof(IContentType).IsAssignableFrom(type)) itemType = PublishedItemType.Content;
|
||||
else if (typeof(IMediaType).IsAssignableFrom(type)) itemType = PublishedItemType.Media;
|
||||
else if (typeof(IMemberType).IsAssignableFrom(type)) itemType = PublishedItemType.Member;
|
||||
return itemType;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Umbraco.Core.Models
|
||||
/// the icon (eg. <c>icon-home</c>) along with an optional CSS class name representing the
|
||||
/// color (eg. <c>icon-blue</c>). Put together, the value for this scenario would be
|
||||
/// <c>icon-home color-blue</c>.
|
||||
///
|
||||
///
|
||||
/// If a class name for the color isn't specified, the icon color will default to black.
|
||||
/// </summary>
|
||||
string Icon { get; set; }
|
||||
@@ -48,6 +48,16 @@ namespace Umbraco.Core.Models
|
||||
/// </remarks>
|
||||
bool IsContainer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this content type is for an element.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>By default a content type is for a true media, member or document, but
|
||||
/// it can also be for an element, ie a subset that can for instance be used in
|
||||
/// nested content.</para>
|
||||
/// </remarks>
|
||||
bool IsElement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content variation of the content type.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,13 +4,18 @@
|
||||
/// The type of published element.
|
||||
/// </summary>
|
||||
/// <remarks>Can be a simple element, or a document, a media, a member.</remarks>
|
||||
public enum PublishedItemType // fixme - need to rename to PublishedElementType but then conflicts?
|
||||
public enum PublishedItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// Unknown.
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// An element.
|
||||
/// </summary>
|
||||
Element,
|
||||
|
||||
/// <summary>
|
||||
/// A document.
|
||||
/// </summary>
|
||||
|
||||
@@ -41,6 +41,10 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[Constraint(Default = "0")]
|
||||
public bool IsContainer { get; set; }
|
||||
|
||||
[Column("isElement")]
|
||||
[Constraint(Default = "0")]
|
||||
public bool IsElement { get; set; }
|
||||
|
||||
[Column("allowAtRoot")]
|
||||
[Constraint(Default = "0")]
|
||||
public bool AllowAtRoot { get; set; }
|
||||
|
||||
@@ -107,6 +107,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
entity.CreatorId = dto.NodeDto.UserId ?? Constants.Security.UnknownUserId;
|
||||
entity.AllowedAsRoot = dto.AllowAtRoot;
|
||||
entity.IsContainer = dto.IsContainer;
|
||||
entity.IsElement = dto.IsElement;
|
||||
entity.Trashed = dto.NodeDto.Trashed;
|
||||
entity.Variations = (ContentVariation) dto.Variations;
|
||||
}
|
||||
@@ -132,6 +133,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
NodeId = entity.Id,
|
||||
AllowAtRoot = entity.AllowedAsRoot,
|
||||
IsContainer = entity.IsContainer,
|
||||
IsElement = entity.IsElement,
|
||||
Variations = (byte) entity.Variations,
|
||||
NodeDto = BuildNodeDto(entity, nodeObjectType)
|
||||
};
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.Description, dto => dto.Description);
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.IsElement, dto => dto.IsElement);
|
||||
CacheMap<ContentType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.Description, dto => dto.Description);
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.IsElement, dto => dto.IsElement);
|
||||
CacheMap<MediaType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.Description, dto => dto.Description);
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.Icon, dto => dto.Icon);
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.IsContainer, dto => dto.IsContainer);
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.IsElement, dto => dto.IsElement);
|
||||
CacheMap<MemberType, ContentTypeDto>(src => src.Thumbnail, dto => dto.Thumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1283,7 +1283,7 @@ AND umbracoNode.id <> @id",
|
||||
if (db == null) throw new ArgumentNullException(nameof(db));
|
||||
|
||||
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
@@ -1384,6 +1384,7 @@ AND umbracoNode.id <> @id",
|
||||
Description = currCt.ctDesc,
|
||||
Icon = currCt.ctIcon,
|
||||
IsContainer = currCt.ctIsContainer,
|
||||
IsElement = currCt.ctIsElement,
|
||||
NodeId = currCt.ctId,
|
||||
PrimaryKey = currCt.ctPk,
|
||||
Thumbnail = currCt.ctThumb,
|
||||
@@ -1422,7 +1423,7 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId,
|
||||
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc, cmsContentType.variations as ctVariations,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.IsElement as ctIsElement, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
@@ -1559,6 +1560,7 @@ AND umbracoNode.id <> @id",
|
||||
Description = currCt.ctDesc,
|
||||
Icon = currCt.ctIcon,
|
||||
IsContainer = currCt.ctIsContainer,
|
||||
IsElement = currCt.ctIsElement,
|
||||
NodeId = currCt.ctId,
|
||||
PrimaryKey = currCt.ctPk,
|
||||
Thumbnail = currCt.ctThumb,
|
||||
|
||||
@@ -319,7 +319,7 @@ namespace Umbraco.Core.Runtime
|
||||
/// Gets a profiler.
|
||||
/// </summary>
|
||||
protected virtual IProfiler GetProfiler()
|
||||
=> new LogProfiler(ProfilingLogger);
|
||||
=> new LogProfiler(Logger);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application caches.
|
||||
|
||||
@@ -7,27 +7,32 @@ namespace Umbraco.Core.Scoping
|
||||
internal class ScopeContext : IScopeContext, IInstanceIdentifiable
|
||||
{
|
||||
private Dictionary<string, IEnlistedObject> _enlisted;
|
||||
private bool _exiting;
|
||||
|
||||
public void ScopeExit(bool completed)
|
||||
{
|
||||
if (_enlisted == null)
|
||||
return;
|
||||
|
||||
_exiting = true;
|
||||
// fixme - can we create infinite loops?
|
||||
// fixme - what about nested events? will they just be plainly ignored = really bad?
|
||||
|
||||
List<Exception> exceptions = null;
|
||||
foreach (var enlisted in _enlisted.Values.OrderBy(x => x.Priority))
|
||||
List<IEnlistedObject> orderedEnlisted;
|
||||
while ((orderedEnlisted = _enlisted.Values.OrderBy(x => x.Priority).ToList()).Count > 0)
|
||||
{
|
||||
try
|
||||
_enlisted.Clear();
|
||||
foreach (var enlisted in orderedEnlisted)
|
||||
{
|
||||
enlisted.Execute(completed);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (exceptions == null)
|
||||
exceptions = new List<Exception>();
|
||||
exceptions.Add(e);
|
||||
try
|
||||
{
|
||||
enlisted.Execute(completed);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (exceptions == null)
|
||||
exceptions = new List<Exception>();
|
||||
exceptions.Add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +79,6 @@ namespace Umbraco.Core.Scoping
|
||||
|
||||
public T Enlist<T>(string key, Func<T> creator, Action<bool, T> action = null, int priority = 100)
|
||||
{
|
||||
if (_exiting)
|
||||
throw new InvalidOperationException("Cannot enlist now, context is exiting.");
|
||||
|
||||
var enlistedObjects = _enlisted ?? (_enlisted = new Dictionary<string, IEnlistedObject>());
|
||||
|
||||
if (enlistedObjects.TryGetValue(key, out var enlisted))
|
||||
|
||||
@@ -337,7 +337,8 @@ namespace Umbraco.Core.Services
|
||||
new XElement("Thumbnail", contentType.Thumbnail),
|
||||
new XElement("Description", contentType.Description),
|
||||
new XElement("AllowAtRoot", contentType.AllowedAsRoot.ToString()),
|
||||
new XElement("IsListView", contentType.IsContainer.ToString()));
|
||||
new XElement("IsListView", contentType.IsContainer.ToString()),
|
||||
new XElement("IsElement", contentType.IsElement.ToString()));
|
||||
|
||||
var masterContentType = contentType.ContentTypeComposition.FirstOrDefault(x => x.Id == contentType.ParentId);
|
||||
if(masterContentType != null)
|
||||
|
||||
@@ -578,6 +578,10 @@ namespace Umbraco.Core.Services.Implement
|
||||
if (isListView != null)
|
||||
contentType.IsContainer = isListView.Value.InvariantEquals("true");
|
||||
|
||||
var isElement = infoElement.Element("IsElement");
|
||||
if (isElement != null)
|
||||
contentType.IsElement = isElement.Value.InvariantEquals("true");
|
||||
|
||||
//Name of the master corresponds to the parent and we need to ensure that the Parent Id is set
|
||||
var masterElement = infoElement.Element("Master");
|
||||
if (masterElement != null)
|
||||
|
||||
@@ -196,6 +196,7 @@
|
||||
<Compile Include="Composing\LightInject\LightInjectContainer.cs" />
|
||||
<Compile Include="Composing\LightInject\MixedLightInjectScopeManagerProvider.cs" />
|
||||
<Compile Include="Composing\OrderedCollectionBuilderBase.cs" />
|
||||
<Compile Include="Composing\TargetedServiceFactory.cs" />
|
||||
<Compile Include="Composing\TypeFinder.cs" />
|
||||
<Compile Include="Composing\TypeHelper.cs" />
|
||||
<Compile Include="Composing\TypeLoader.cs" />
|
||||
@@ -343,6 +344,7 @@
|
||||
<Compile Include="IO\IMediaPathScheme.cs" />
|
||||
<Compile Include="IO\MediaPathSchemes\OriginalMediaPathScheme.cs" />
|
||||
<Compile Include="IO\MediaPathSchemes\TwoGuidsMediaPathScheme.cs" />
|
||||
<Compile Include="IO\SupportingFileSystems.cs" />
|
||||
<Compile Include="KeyValuePairExtensions.cs" />
|
||||
<Compile Include="Logging\IProfilingLogger.cs" />
|
||||
<Compile Include="Logging\LogHttpRequest.cs" />
|
||||
@@ -375,6 +377,7 @@
|
||||
<Compile Include="Migrations\Upgrade\V_7_9_0\AddUmbracoAuditTable.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_9_0\AddUmbracoConsentTable.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_9_0\CreateSensitiveDataUserGroup.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\AddContentTypeIsElementColumn.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\AddLogTableColumns.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\AddTypedLabels.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\AddVariationTables1A.cs" />
|
||||
|
||||
@@ -42,9 +42,9 @@ namespace Umbraco.Examine
|
||||
var values = new Dictionary<string, IEnumerable<object>>
|
||||
{
|
||||
{"icon", c.ContentType.Icon.Yield()},
|
||||
{UmbracoExamineIndex.PublishedFieldName, new object[] {c.Published ? 1 : 0}}, //Always add invariant published value
|
||||
{UmbracoExamineIndex.PublishedFieldName, new object[] {c.Published ? "y" : "n"}}, //Always add invariant published value
|
||||
{"id", new object[] {c.Id}},
|
||||
{"key", new object[] {c.Key}},
|
||||
{UmbracoExamineIndex.NodeKeyFieldName, new object[] {c.Key}},
|
||||
{"parentID", new object[] {c.Level > 1 ? c.ParentId : -1}},
|
||||
{"level", new object[] {c.Level}},
|
||||
{"creatorID", new object[] {c.CreatorId}},
|
||||
@@ -61,12 +61,12 @@ namespace Umbraco.Examine
|
||||
{"writerName",(c.GetWriterProfile(_userService)?.Name ?? "??").Yield() },
|
||||
{"writerID", new object[] {c.WriterId}},
|
||||
{"templateID", new object[] {c.TemplateId ?? 0}},
|
||||
{UmbracoContentIndex.VariesByCultureFieldName, new object[] {0}},
|
||||
{UmbracoContentIndex.VariesByCultureFieldName, new object[] {"n"}},
|
||||
};
|
||||
|
||||
if (isVariant)
|
||||
{
|
||||
values[UmbracoContentIndex.VariesByCultureFieldName] = new object[] { 1 };
|
||||
values[UmbracoContentIndex.VariesByCultureFieldName] = new object[] { "y" };
|
||||
|
||||
foreach (var culture in c.AvailableCultures)
|
||||
{
|
||||
@@ -76,7 +76,7 @@ namespace Umbraco.Examine
|
||||
values[$"nodeName_{lowerCulture}"] = PublishedValuesOnly
|
||||
? c.GetPublishName(culture).Yield()
|
||||
: c.GetCultureName(culture).Yield();
|
||||
values[$"{UmbracoExamineIndex.PublishedFieldName}_{lowerCulture}"] = (c.IsCulturePublished(culture) ? 1 : 0).Yield<object>();
|
||||
values[$"{UmbracoExamineIndex.PublishedFieldName}_{lowerCulture}"] = (c.IsCulturePublished(culture) ? "y" : "n").Yield<object>();
|
||||
values[$"updateDate_{lowerCulture}"] = PublishedValuesOnly
|
||||
? c.GetPublishDate(culture).Yield<object>()
|
||||
: c.GetUpdateDate(culture).Yield<object>();
|
||||
|
||||
@@ -95,17 +95,17 @@ namespace Umbraco.Examine
|
||||
if (!valueSet.Values.TryGetValue(UmbracoExamineIndex.PublishedFieldName, out var published))
|
||||
return ValueSetValidationResult.Failed;
|
||||
|
||||
if (!published[0].Equals(1))
|
||||
if (!published[0].Equals("y"))
|
||||
return ValueSetValidationResult.Failed;
|
||||
|
||||
//deal with variants, if there are unpublished variants than we need to remove them from the value set
|
||||
if (valueSet.Values.TryGetValue(UmbracoContentIndex.VariesByCultureFieldName, out var variesByCulture)
|
||||
&& variesByCulture.Count > 0 && variesByCulture[0].Equals(1))
|
||||
&& variesByCulture.Count > 0 && variesByCulture[0].Equals("y"))
|
||||
{
|
||||
//so this valueset is for a content that varies by culture, now check for non-published cultures and remove those values
|
||||
foreach(var publishField in valueSet.Values.Where(x => x.Key.StartsWith($"{UmbracoExamineIndex.PublishedFieldName}_")).ToList())
|
||||
{
|
||||
if (publishField.Value.Count <= 0 || !publishField.Value[0].Equals(1))
|
||||
if (publishField.Value.Count <= 0 || !publishField.Value[0].Equals("y"))
|
||||
{
|
||||
//this culture is not published, so remove all of these culture values
|
||||
var cultureSuffix = publishField.Key.Substring(publishField.Key.LastIndexOf('_'));
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Examine;
|
||||
using Examine.LuceneEngine.Providers;
|
||||
using Lucene.Net.Analysis;
|
||||
@@ -7,6 +9,7 @@ using Lucene.Net.Index;
|
||||
using Lucene.Net.QueryParsers;
|
||||
using Lucene.Net.Search;
|
||||
using Lucene.Net.Store;
|
||||
using Umbraco.Core;
|
||||
using Version = Lucene.Net.Util.Version;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -15,9 +18,35 @@ namespace Umbraco.Examine
|
||||
/// <summary>
|
||||
/// Extension methods for the LuceneIndex
|
||||
/// </summary>
|
||||
internal static class ExamineExtensions
|
||||
public static class ExamineExtensions
|
||||
{
|
||||
public static bool TryParseLuceneQuery(string query)
|
||||
/// <summary>
|
||||
/// Matches a culture iso name suffix
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// myFieldName_en-us will match the "en-us"
|
||||
/// </remarks>
|
||||
internal static readonly Regex CultureIsoCodeFieldNameMatchExpression = new Regex("^([_\\w]+)_([a-z]{2}-[a-z0-9]{2,4})$", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all index fields that are culture specific (suffixed)
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="culture"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> GetCultureFields(this IUmbracoIndex index, string culture)
|
||||
{
|
||||
var allFields = index.GetFields();
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var field in allFields)
|
||||
{
|
||||
var match = CultureIsoCodeFieldNameMatchExpression.Match(field);
|
||||
if (match.Success && match.Groups.Count == 3 && culture.InvariantEquals(match.Groups[2].Value))
|
||||
yield return field;
|
||||
}
|
||||
}
|
||||
|
||||
internal 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
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Examine
|
||||
{
|
||||
{"icon", m.ContentType.Icon.Yield()},
|
||||
{"id", new object[] {m.Id}},
|
||||
{"key", new object[] {m.Key}},
|
||||
{UmbracoExamineIndex.NodeKeyFieldName, new object[] {m.Key}},
|
||||
{"parentID", new object[] {m.Level > 1 ? m.ParentId : -1}},
|
||||
{"level", new object[] {m.Level}},
|
||||
{"creatorID", new object[] {m.CreatorId}},
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Examine
|
||||
{
|
||||
{"icon", m.ContentType.Icon.Yield()},
|
||||
{"id", new object[] {m.Id}},
|
||||
{"key", new object[] {m.Key}},
|
||||
{UmbracoExamineIndex.NodeKeyFieldName, new object[] {m.Key}},
|
||||
{"parentID", new object[] {m.Level > 1 ? m.ParentId : -1}},
|
||||
{"level", new object[] {m.Level}},
|
||||
{"creatorID", new object[] {m.CreatorId}},
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- note: NuGet deals with transitive references now -->
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta072" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta078" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="NPoco" Version="3.9.4" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using Examine;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Examine;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Examine
|
||||
{
|
||||
@@ -30,7 +33,7 @@ namespace Umbraco.Examine
|
||||
new FieldDefinition("createDate", FieldDefinitionTypes.DateTime),
|
||||
new FieldDefinition("updateDate", FieldDefinitionTypes.DateTime),
|
||||
|
||||
new FieldDefinition("key", FieldDefinitionTypes.InvariantCultureIgnoreCase),
|
||||
new FieldDefinition(UmbracoExamineIndex.NodeKeyFieldName, FieldDefinitionTypes.InvariantCultureIgnoreCase),
|
||||
new FieldDefinition("version", FieldDefinitionTypes.Raw),
|
||||
new FieldDefinition("nodeType", FieldDefinitionTypes.InvariantCultureIgnoreCase),
|
||||
new FieldDefinition("template", FieldDefinitionTypes.Raw),
|
||||
@@ -40,36 +43,54 @@ namespace Umbraco.Examine
|
||||
new FieldDefinition("email", FieldDefinitionTypes.EmailAddress),
|
||||
|
||||
new FieldDefinition(UmbracoExamineIndex.PublishedFieldName, FieldDefinitionTypes.Raw),
|
||||
new FieldDefinition(UmbracoExamineIndex.NodeKeyFieldName, FieldDefinitionTypes.Raw),
|
||||
new FieldDefinition(UmbracoExamineIndex.IndexPathFieldName, FieldDefinitionTypes.Raw),
|
||||
new FieldDefinition(UmbracoExamineIndex.IconFieldName, FieldDefinitionTypes.Raw)
|
||||
new FieldDefinition(UmbracoExamineIndex.IconFieldName, FieldDefinitionTypes.Raw),
|
||||
new FieldDefinition(UmbracoContentIndex.VariesByCultureFieldName, FieldDefinitionTypes.Raw),
|
||||
};
|
||||
|
||||
///// <summary>
|
||||
///// Overridden to dynamically add field definitions for culture variations
|
||||
///// </summary>
|
||||
///// <param name="fieldName"></param>
|
||||
///// <param name="fieldDefinition"></param>
|
||||
///// <returns></returns>
|
||||
//public override bool TryGetValue(string fieldName, out FieldDefinition fieldDefinition)
|
||||
//{
|
||||
// var result = base.TryGetValue(fieldName, out fieldDefinition);
|
||||
// if (result) return true;
|
||||
|
||||
// //if the fieldName is not suffixed with _iso-Code
|
||||
// var underscoreIndex = fieldName.LastIndexOf('_');
|
||||
// if (underscoreIndex == -1) return false;
|
||||
/// <summary>
|
||||
/// Overridden to dynamically add field definitions for culture variations
|
||||
/// </summary>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <param name="fieldDefinition"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// We need to do this so that we don't have to maintain a huge static list of all field names and their definitions
|
||||
/// otherwise we'd have to dynamically add/remove definitions anytime languages are added/removed, etc...
|
||||
/// For example, we have things like `nodeName` and `__Published` which are also used for culture fields like `nodeName_en-us`
|
||||
/// and we don't want to have a full static list of all of these definitions when we can just define the one definition and then
|
||||
/// dynamically apply that to culture specific fields.
|
||||
///
|
||||
/// There is a caveat to this however, when a field definition is found for a non-culture field we will create and store a new field
|
||||
/// definition for that culture so that the next time it needs to be looked up and used we are not allocating more objects. This does mean
|
||||
/// however that if a language is deleted, the field definitions for that language will still exist in memory. This isn't going to cause any
|
||||
/// problems and the mem will be cleared on next site restart but it's worth pointing out.
|
||||
/// </remarks>
|
||||
public override bool TryGetValue(string fieldName, out FieldDefinition fieldDefinition)
|
||||
{
|
||||
if (base.TryGetValue(fieldName, out fieldDefinition))
|
||||
return true;
|
||||
|
||||
//before we use regex to match do some faster simple matching since this is going to execute quite a lot
|
||||
if (!fieldName.Contains("_") || !fieldName.Contains("-"))
|
||||
return false;
|
||||
|
||||
var match = ExamineExtensions.CultureIsoCodeFieldNameMatchExpression.Match(fieldName);
|
||||
if (match.Success && match.Groups.Count == 3)
|
||||
{
|
||||
var nonCultureFieldName = match.Groups[1].Value;
|
||||
//check if there's a definition for this and if so return the field definition for the culture field based on the non-culture field
|
||||
if (base.TryGetValue(nonCultureFieldName, out var existingFieldDefinition))
|
||||
{
|
||||
//now add a new field def
|
||||
fieldDefinition = GetOrAdd(fieldName, s => new FieldDefinition(s, existingFieldDefinition.Type));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// var isoCode = fieldName.Substring(underscoreIndex);
|
||||
// if (isoCode.Length < 6) return false; //invalid isoCode
|
||||
|
||||
// var hyphenIndex = isoCode.IndexOf('-');
|
||||
// if (hyphenIndex != 3) return false; //invalid isoCode
|
||||
|
||||
// //we'll assume this is a valid isoCode
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,35 +32,6 @@ namespace Umbraco.Examine
|
||||
base(name, luceneDirectory, fieldDefinitions, analyzer, profilingLogger, validator)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden to ensure that the umbraco system field definitions are in place
|
||||
/// </summary>
|
||||
/// <param name="indexValueTypesFactory"></param>
|
||||
/// <returns></returns>
|
||||
protected override FieldValueTypeCollection CreateFieldValueTypes(IReadOnlyDictionary<string, IFieldValueTypeFactory> indexValueTypesFactory = null)
|
||||
{
|
||||
var keyDef = new FieldDefinition("__key", FieldDefinitionTypes.Raw);
|
||||
FieldDefinitionCollection.TryAdd(keyDef);
|
||||
|
||||
return base.CreateFieldValueTypes(indexValueTypesFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure some custom values are added to the index
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected override void OnTransformingIndexValues(IndexingItemEventArgs e)
|
||||
{
|
||||
base.OnTransformingIndexValues(e);
|
||||
|
||||
if (e.ValueSet.Values.TryGetValue("key", out var key) && e.ValueSet.Values.ContainsKey("__key") == false)
|
||||
{
|
||||
//double __ prefix means it will be indexed as culture invariant
|
||||
e.ValueSet.Values["__key"] = key;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace Umbraco.Tests.Cache.PublishedCache
|
||||
{"creatorName", "Shannon"}
|
||||
};
|
||||
|
||||
var result = new SearchResult("1234", 1, 1, () => fields.ToDictionary(x => x.Key, x => new List<string> { x.Value }));
|
||||
var result = new SearchResult("1234", 1, () => fields.ToDictionary(x => x.Key, x => new List<string> { x.Value }));
|
||||
|
||||
var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new StaticCacheProvider(), ContentTypesCache);
|
||||
var doc = store.CreateFromCacheValues(store.ConvertFromSearchResult(result));
|
||||
|
||||
@@ -194,8 +194,8 @@ namespace Umbraco.Tests.Composing
|
||||
var register = GetRegister();
|
||||
|
||||
// define two instances
|
||||
register.RegisterInstance(typeof(Thing1), new Thing1());
|
||||
register.RegisterInstance(typeof(Thing1), new Thing2());
|
||||
register.Register(typeof(Thing1), new Thing1());
|
||||
register.Register(typeof(Thing1), new Thing2());
|
||||
|
||||
var factory = register.CreateFactory();
|
||||
|
||||
@@ -212,8 +212,8 @@ namespace Umbraco.Tests.Composing
|
||||
var register = GetRegister();
|
||||
|
||||
// define two instances
|
||||
register.RegisterInstance(typeof(IThing), new Thing1());
|
||||
register.RegisterInstance(typeof(IThing), new Thing2());
|
||||
register.Register(typeof(IThing), new Thing1());
|
||||
register.Register(typeof(IThing), new Thing2());
|
||||
|
||||
var factory = register.CreateFactory();
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace Umbraco.Tests.PublishedContent
|
||||
[Test]
|
||||
public void PublishedContentQueryTypedContentList()
|
||||
{
|
||||
var query = new PublishedContentQuery(UmbracoContext.Current.ContentCache, UmbracoContext.Current.MediaCache);
|
||||
var query = new PublishedContentQuery(UmbracoContext.Current.ContentCache, UmbracoContext.Current.MediaCache, UmbracoContext.Current.VariationContextAccessor);
|
||||
var result = query.Content(new[] { 1, 2, 4 }).ToArray();
|
||||
Assert.AreEqual(2, result.Length);
|
||||
Assert.AreEqual(1, result[0].Id);
|
||||
|
||||
@@ -69,8 +69,9 @@ namespace Umbraco.Tests.PublishedContent
|
||||
factory.CreatePropertyType("testRecursive", 1),
|
||||
};
|
||||
var compositionAliases = new[] { "MyCompositionAlias" };
|
||||
var type = new AutoPublishedContentType(0, "anything", compositionAliases, propertyTypes);
|
||||
ContentTypesCache.GetPublishedContentTypeByAlias = alias => type;
|
||||
var anythingType = new AutoPublishedContentType(0, "anything", compositionAliases, propertyTypes);
|
||||
var homeType = new AutoPublishedContentType(0, "home", compositionAliases, propertyTypes);
|
||||
ContentTypesCache.GetPublishedContentTypeByAlias = alias => alias.InvariantEquals("home") ? homeType : anythingType;
|
||||
}
|
||||
|
||||
protected override TypeLoader CreateTypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger)
|
||||
@@ -233,10 +234,10 @@ namespace Umbraco.Tests.PublishedContent
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("Fails as long as PublishedContentModel is internal.")] // fixme
|
||||
public void Is_Last_From_Where_Filter2()
|
||||
{
|
||||
var doc = GetNode(1173);
|
||||
var ct = doc.ContentType;
|
||||
|
||||
var items = doc.Children
|
||||
.Select(x => x.CreateModel()) // linq, returns IEnumerable<IPublishedContent>
|
||||
@@ -455,11 +456,11 @@ namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
var doc = GetNode(1046); // has child nodes
|
||||
|
||||
var model = doc.FirstChild<Anything>(x => true); // predicate
|
||||
var model = doc.FirstChild<Home>(x => true); // predicate
|
||||
|
||||
Assert.IsNotNull(model);
|
||||
Assert.IsTrue(model.Id == 1173);
|
||||
Assert.IsInstanceOf<Anything>(model);
|
||||
Assert.IsInstanceOf<Home>(model);
|
||||
Assert.IsInstanceOf<IPublishedContent>(model);
|
||||
|
||||
doc = GetNode(1175); // does not have child nodes
|
||||
|
||||
@@ -540,7 +540,7 @@ namespace Umbraco.Tests.Scoping
|
||||
var scopeProvider = ScopeProvider;
|
||||
|
||||
bool? completed = null;
|
||||
Exception exception = null;
|
||||
bool? completed2 = null;
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
using (var scope = scopeProvider.CreateScope())
|
||||
@@ -551,15 +551,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
// at that point the scope is gone, but the context is still there
|
||||
var ambientContext = scopeProvider.AmbientContext;
|
||||
|
||||
try
|
||||
{
|
||||
ambientContext.Enlist("another", c2 => { });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exception = e;
|
||||
}
|
||||
ambientContext.Enlist("another", c2 => { completed2 = c2; });
|
||||
});
|
||||
if (complete)
|
||||
scope.Complete();
|
||||
@@ -567,8 +559,8 @@ namespace Umbraco.Tests.Scoping
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientContext);
|
||||
Assert.IsNotNull(completed);
|
||||
Assert.IsNotNull(exception);
|
||||
Assert.IsInstanceOf<InvalidOperationException>(exception);
|
||||
Assert.AreEqual(complete,completed.Value);
|
||||
Assert.AreEqual(complete, completed2.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -22,6 +22,36 @@ namespace Umbraco.Tests.Services
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)]
|
||||
public class ContentTypeServiceTests : TestWithSomeContentBase
|
||||
{
|
||||
[Test]
|
||||
public void CanSaveAndGetIsElement()
|
||||
{
|
||||
//create content type with a property type that varies by culture
|
||||
IContentType contentType = MockedContentTypes.CreateBasicContentType();
|
||||
contentType.Variations = ContentVariation.Nothing;
|
||||
var contentCollection = new PropertyTypeCollection(true);
|
||||
contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext)
|
||||
{
|
||||
Alias = "title",
|
||||
Name = "Title",
|
||||
Description = "",
|
||||
Mandatory = false,
|
||||
SortOrder = 1,
|
||||
DataTypeId = -88,
|
||||
Variations = ContentVariation.Nothing
|
||||
});
|
||||
contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 });
|
||||
ServiceContext.ContentTypeService.Save(contentType);
|
||||
|
||||
contentType = ServiceContext.ContentTypeService.Get(contentType.Id);
|
||||
Assert.IsFalse(contentType.IsElement);
|
||||
|
||||
contentType.IsElement = true;
|
||||
ServiceContext.ContentTypeService.Save(contentType);
|
||||
|
||||
contentType = ServiceContext.ContentTypeService.Get(contentType.Id);
|
||||
Assert.IsTrue(contentType.IsElement);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Change_Content_Type_Variation_Clears_Redirects()
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="7.0.1" />
|
||||
<PackageReference Include="Castle.Core" Version="4.2.1" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta072" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta078" />
|
||||
<PackageReference Include="HtmlAgilityPack">
|
||||
<Version>1.8.9</Version>
|
||||
</PackageReference>
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
{
|
||||
["hello"] = "world",
|
||||
["path"] = "-1,555",
|
||||
[UmbracoExamineIndex.PublishedFieldName] = 1
|
||||
[UmbracoExamineIndex.PublishedFieldName] = "y"
|
||||
}));
|
||||
Assert.AreEqual(ValueSetValidationResult.Valid, result);
|
||||
}
|
||||
@@ -213,7 +213,7 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
{
|
||||
["hello"] = "world",
|
||||
["path"] = "-1,555",
|
||||
[UmbracoExamineIndex.PublishedFieldName] = 0
|
||||
[UmbracoExamineIndex.PublishedFieldName] = "n"
|
||||
}));
|
||||
Assert.AreEqual(ValueSetValidationResult.Failed, result);
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
{
|
||||
["hello"] = "world",
|
||||
["path"] = "-1,555",
|
||||
[UmbracoExamineIndex.PublishedFieldName] = 1
|
||||
[UmbracoExamineIndex.PublishedFieldName] = "y"
|
||||
}));
|
||||
Assert.AreEqual(ValueSetValidationResult.Valid, result);
|
||||
}
|
||||
@@ -237,8 +237,8 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
{
|
||||
["hello"] = "world",
|
||||
["path"] = "-1,555",
|
||||
[UmbracoContentIndex.VariesByCultureFieldName] = 1,
|
||||
[UmbracoExamineIndex.PublishedFieldName] = 0
|
||||
[UmbracoContentIndex.VariesByCultureFieldName] = "y",
|
||||
[UmbracoExamineIndex.PublishedFieldName] = "n"
|
||||
}));
|
||||
Assert.AreEqual(ValueSetValidationResult.Failed, result);
|
||||
|
||||
@@ -247,8 +247,8 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
{
|
||||
["hello"] = "world",
|
||||
["path"] = "-1,555",
|
||||
[UmbracoContentIndex.VariesByCultureFieldName] = 1,
|
||||
[UmbracoExamineIndex.PublishedFieldName] = 1
|
||||
[UmbracoContentIndex.VariesByCultureFieldName] = "y",
|
||||
[UmbracoExamineIndex.PublishedFieldName] = "y"
|
||||
}));
|
||||
Assert.AreEqual(ValueSetValidationResult.Valid, result);
|
||||
|
||||
@@ -257,14 +257,14 @@ namespace Umbraco.Tests.UmbracoExamine
|
||||
{
|
||||
["hello"] = "world",
|
||||
["path"] = "-1,555",
|
||||
[UmbracoContentIndex.VariesByCultureFieldName] = 1,
|
||||
[$"{UmbracoExamineIndex.PublishedFieldName}_en-us"] = 1,
|
||||
[UmbracoContentIndex.VariesByCultureFieldName] = "y",
|
||||
[$"{UmbracoExamineIndex.PublishedFieldName}_en-us"] = "y",
|
||||
["hello_en-us"] = "world",
|
||||
["title_en-us"] = "my title",
|
||||
[$"{UmbracoExamineIndex.PublishedFieldName}_es-es"] = 0,
|
||||
[$"{UmbracoExamineIndex.PublishedFieldName}_es-es"] = "n",
|
||||
["hello_es-ES"] = "world",
|
||||
["title_es-ES"] = "my title",
|
||||
[UmbracoExamineIndex.PublishedFieldName] = 1
|
||||
[UmbracoExamineIndex.PublishedFieldName] = "y"
|
||||
});
|
||||
Assert.AreEqual(10, valueSet.Values.Count());
|
||||
Assert.IsTrue(valueSet.Values.ContainsKey($"{UmbracoExamineIndex.PublishedFieldName}_es-es"));
|
||||
|
||||
@@ -29,5 +29,30 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
var output = _htmlHelper.Wrap("div", "hello world", new {style = "color:red;", onclick = "void();"});
|
||||
Assert.AreEqual("<div style=\"color:red;\" onclick=\"void();\">hello world</div>", output.ToHtmlString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetRelatedLinkHtml_Simple()
|
||||
{
|
||||
var relatedLink = new Umbraco.Web.Models.RelatedLink {
|
||||
Caption = "Link Caption",
|
||||
NewWindow = true,
|
||||
Link = "https://www.google.com/"
|
||||
};
|
||||
var output = _htmlHelper.GetRelatedLinkHtml(relatedLink);
|
||||
Assert.AreEqual("<a href=\"https://www.google.com/\" target=\"_blank\">Link Caption</a>", output.ToHtmlString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetRelatedLinkHtml_HtmlAttributes()
|
||||
{
|
||||
var relatedLink = new Umbraco.Web.Models.RelatedLink
|
||||
{
|
||||
Caption = "Link Caption",
|
||||
NewWindow = true,
|
||||
Link = "https://www.google.com/"
|
||||
};
|
||||
var output = _htmlHelper.GetRelatedLinkHtml(relatedLink, new { @class = "test-class"});
|
||||
Assert.AreEqual("<a class=\"test-class\" href=\"https://www.google.com/\" target=\"_blank\">Link Caption</a>", output.ToHtmlString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,6 +248,17 @@ gulp.task('dependencies', function () {
|
||||
"src": ["./node_modules/bootstrap-social/bootstrap-social.css"],
|
||||
"base": "./node_modules/bootstrap-social"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "angular-chart.js",
|
||||
"src": ["./node_modules/angular-chart.js/dist/angular-chart.min.js"],
|
||||
"base": "./node_modules/angular-chart.js/dist"
|
||||
},
|
||||
{
|
||||
"name": "chart.js",
|
||||
"src": ["./node_modules/chart.js/dist/chart.min.js"],
|
||||
"base": "./node_modules/chart.js/dist"
|
||||
},
|
||||
{
|
||||
"name": "clipboard",
|
||||
"src": ["./node_modules/clipboard/dist/clipboard.min.js"],
|
||||
|
||||
56
src/Umbraco.Web.UI.Client/package-lock.json
generated
56
src/Umbraco.Web.UI.Client/package-lock.json
generated
@@ -852,6 +852,26 @@
|
||||
"resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.7.5.tgz",
|
||||
"integrity": "sha512-kU/fHIGf2a4a3bH7E1tzALTHk+QfoUSCK9fEcMFisd6ZWvNDwPzXWAilItqOC3EDiAXPmGHaNc9/aXiD9xrAxQ=="
|
||||
},
|
||||
"angular-chart.js": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/angular-chart.js/-/angular-chart.js-1.1.1.tgz",
|
||||
"integrity": "sha1-SfDhjQgXYrbUyXkeSHr/L7sw9a4=",
|
||||
"requires": {
|
||||
"angular": "1.x",
|
||||
"chart.js": "2.3.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"chart.js": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.3.0.tgz",
|
||||
"integrity": "sha1-QEYOSOLEF8BfwzJc2E97AA3H19Y=",
|
||||
"requires": {
|
||||
"chartjs-color": "^2.0.0",
|
||||
"moment": "^2.10.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"angular-cookies": {
|
||||
"version": "1.7.5",
|
||||
"resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.7.5.tgz",
|
||||
@@ -1970,6 +1990,39 @@
|
||||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
||||
"dev": true
|
||||
},
|
||||
"chart.js": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.3.tgz",
|
||||
"integrity": "sha512-3+7k/DbR92m6BsMUYP6M0dMsMVZpMnwkUyNSAbqolHKsbIzH2Q4LWVEHHYq7v0fmEV8whXE0DrjANulw9j2K5g==",
|
||||
"requires": {
|
||||
"chartjs-color": "^2.1.0",
|
||||
"moment": "^2.10.2"
|
||||
}
|
||||
},
|
||||
"chartjs-color": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz",
|
||||
"integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=",
|
||||
"requires": {
|
||||
"chartjs-color-string": "^0.5.0",
|
||||
"color-convert": "^0.5.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"color-convert": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
|
||||
"integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
|
||||
}
|
||||
}
|
||||
},
|
||||
"chartjs-color-string": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz",
|
||||
"integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==",
|
||||
"requires": {
|
||||
"color-name": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz",
|
||||
@@ -2216,8 +2269,7 @@
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"color-string": {
|
||||
"version": "1.5.3",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"ace-builds": "1.4.2",
|
||||
"angular": "1.7.5",
|
||||
"angular-animate": "1.7.5",
|
||||
"angular-chart.js": "^1.1.1",
|
||||
"angular-cookies": "1.7.5",
|
||||
"angular-dynamic-locale": "0.1.37",
|
||||
"angular-i18n": "1.7.5",
|
||||
@@ -20,6 +21,7 @@
|
||||
"angular-ui-sortable": "0.19.0",
|
||||
"animejs": "2.2.0",
|
||||
"bootstrap-social": "5.1.1",
|
||||
"chart.js": "^2.7.3",
|
||||
"clipboard": "2.0.4",
|
||||
"diff": "3.5.0",
|
||||
"flatpickr": "4.5.2",
|
||||
|
||||
@@ -14,7 +14,8 @@ var app = angular.module('umbraco', [
|
||||
'ngMessages',
|
||||
'tmh.dynamicLocale',
|
||||
'ngFileUpload',
|
||||
'LocalStorageModule'
|
||||
'LocalStorageModule',
|
||||
'chart.js'
|
||||
]);
|
||||
|
||||
app.config(['$compileProvider', function ($compileProvider) {
|
||||
@@ -76,7 +77,7 @@ angular.module("umbraco.viewcache", [])
|
||||
var _op = (url.indexOf("?") > 0) ? "&" : "?";
|
||||
url += _op + "umb__rnd=" + rnd;
|
||||
}
|
||||
|
||||
|
||||
return get(url, config);
|
||||
};
|
||||
return $delegate;
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
</pre>
|
||||
|
||||
@param {boolean} checked Set to <code>true</code> or <code>false</code> to toggle the switch.
|
||||
@param {boolean} disabled Set to <code>true</code> or <code>false</code> to disable the switch.
|
||||
@param {callback} onClick The function which should be called when the toggle is clicked.
|
||||
@param {string=} showLabels Set to <code>true</code> or <code>false</code> to show a "On" or "Off" label next to the switch.
|
||||
@param {string=} labelOn Set a custom label for when the switched is turned on. It will default to "On".
|
||||
|
||||
@@ -97,9 +97,9 @@
|
||||
}
|
||||
|
||||
//load in the audit trail if we are currently looking at the INFO tab
|
||||
if (umbVariantContentCtrl) {
|
||||
if (umbVariantContentCtrl && umbVariantContentCtrl.editor) {
|
||||
var activeApp = _.find(umbVariantContentCtrl.editor.content.apps, a => a.active);
|
||||
if (activeApp.alias === "umbInfo") {
|
||||
if (activeApp && activeApp.alias === "umbInfo") {
|
||||
isInfoTab = true;
|
||||
loadAuditTrail();
|
||||
loadRedirectUrls();
|
||||
|
||||
@@ -130,8 +130,7 @@
|
||||
if (!changes.value.isFirstChange() && changes.value.currentValue !== changes.value.previousValue) {
|
||||
|
||||
configureViewModel();
|
||||
//this is required to re-validate
|
||||
vm.tagEditorForm.tagCount.$setViewValue(vm.viewModel.length);
|
||||
reValidate()
|
||||
|
||||
}
|
||||
}
|
||||
@@ -182,6 +181,8 @@
|
||||
else {
|
||||
vm.onValueChanged({ value: [] });
|
||||
}
|
||||
|
||||
reValidate();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,7 +190,7 @@
|
||||
*/
|
||||
function validateMandatory() {
|
||||
return {
|
||||
isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0),
|
||||
isValid: !vm.validation.mandatory || (vm.viewModel != null && vm.viewModel.length > 0)|| (vm.value != null && vm.value.length > 0),
|
||||
errorMsg: "Value cannot be empty",
|
||||
errorKey: "required"
|
||||
};
|
||||
@@ -271,6 +272,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
function reValidate() {
|
||||
//this is required to re-validate
|
||||
vm.tagEditorForm.tagCount.$setViewValue(vm.viewModel.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -86,20 +86,21 @@ angular.module("umbraco.directives")
|
||||
function generateAlias(value) {
|
||||
|
||||
if (generateAliasTimeout) {
|
||||
$timeout.cancel(generateAliasTimeout);
|
||||
$timeout.cancel(generateAliasTimeout);
|
||||
}
|
||||
|
||||
if( value !== undefined && value !== "" && value !== null) {
|
||||
if (value !== undefined && value !== "" && value !== null) {
|
||||
|
||||
scope.alias = "";
|
||||
scope.alias = "";
|
||||
scope.placeholderText = scope.labels.busy;
|
||||
|
||||
generateAliasTimeout = $timeout(function () {
|
||||
updateAlias = true;
|
||||
entityResource.getSafeAlias(value, true).then(function (safeAlias) {
|
||||
if (updateAlias) {
|
||||
scope.alias = safeAlias.alias;
|
||||
}
|
||||
scope.alias = safeAlias.alias;
|
||||
}
|
||||
scope.placeholderText = scope.labels.idle;
|
||||
});
|
||||
}, 500);
|
||||
|
||||
@@ -108,7 +109,6 @@ angular.module("umbraco.directives")
|
||||
scope.alias = "";
|
||||
scope.placeholderText = scope.labels.idle;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if alias gets unlocked - stop watching alias
|
||||
@@ -119,17 +119,17 @@ angular.module("umbraco.directives")
|
||||
}));
|
||||
|
||||
// validate custom entered alias
|
||||
eventBindings.push(scope.$watch('alias', function(newValue, oldValue){
|
||||
|
||||
if(scope.alias === "" && bindWatcher === true || scope.alias === null && bindWatcher === true) {
|
||||
// add watcher
|
||||
eventBindings.push(scope.$watch('aliasFrom', function(newValue, oldValue) {
|
||||
if(bindWatcher) {
|
||||
generateAlias(newValue);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
eventBindings.push(scope.$watch('alias', function (newValue, oldValue) {
|
||||
if (scope.alias === "" || scope.alias === null || scope.alias === undefined) {
|
||||
if (bindWatcher === true) {
|
||||
// add watcher
|
||||
eventBindings.push(scope.$watch('aliasFrom', function (newValue, oldValue) {
|
||||
if (bindWatcher) {
|
||||
generateAlias(newValue);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// clean up
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @name umbraco.resources.codefileResource
|
||||
* @description Loads in data for files that contain code such as js scripts, partial views and partial view macros
|
||||
**/
|
||||
function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
function codefileResource($q, $http, umbDataFormatter, umbRequestHelper, localizationService) {
|
||||
|
||||
return {
|
||||
|
||||
@@ -106,13 +106,16 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
*/
|
||||
deleteByPath: function (type, virtualpath) {
|
||||
|
||||
var promise = localizationService.localize("codefile_deleteItemFailed", [virtualpath]);
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"codeFileApiBaseUrl",
|
||||
"Delete",
|
||||
[{ type: type }, { virtualPath: virtualpath}])),
|
||||
"Failed to delete item: " + virtualpath);
|
||||
promise);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -236,13 +239,19 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
*/
|
||||
|
||||
createContainer: function(type, parentId, name) {
|
||||
createContainer: function (type, parentId, name) {
|
||||
|
||||
// Is the parent ID numeric?
|
||||
var key = "codefile_createFolderFailedBy" + (isNaN(parseInt(parentId)) ? "Name" : "Id");
|
||||
|
||||
var promise = localizationService.localize(key, [parentId]);
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl(
|
||||
"codeFileApiBaseUrl",
|
||||
"PostCreateContainer",
|
||||
{ type: type, parentId: parentId, name: encodeURIComponent(name) })),
|
||||
'Failed to create a folder under parent id ' + parentId);
|
||||
promise);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @name umbraco.resources.templateResource
|
||||
* @description Loads in data for templates
|
||||
**/
|
||||
function templateResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
function templateResource($q, $http, umbDataFormatter, umbRequestHelper, localizationService) {
|
||||
|
||||
return {
|
||||
|
||||
@@ -152,13 +152,16 @@ function templateResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
*/
|
||||
deleteById: function(id) {
|
||||
|
||||
var promise = localizationService.localize("template_deleteByIdFailed", [id]);
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"templateApiBaseUrl",
|
||||
"DeleteById",
|
||||
[{ id: id }])),
|
||||
"Failed to delete item " + id);
|
||||
promise);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -162,7 +162,7 @@ When building a custom infinite editor view you can use the same components as a
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function editorService(eventsService, keyboardService) {
|
||||
function editorService(eventsService, keyboardService, $timeout) {
|
||||
|
||||
let editorsKeyboardShorcuts = [];
|
||||
var editors = [];
|
||||
@@ -245,10 +245,14 @@ When building a custom infinite editor view you can use the same components as a
|
||||
|
||||
// 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();
|
||||
|
||||
// delay required to map the properties to the correct editor due
|
||||
// to another delay in the closing animation of the editor
|
||||
$timeout(function() {
|
||||
// rebind keyboard shortcuts for the new editor in focus
|
||||
rebindKeyboardShortcuts();
|
||||
}, 0);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
var saveModel = _.pick(displayModel,
|
||||
'compositeContentTypes', 'isContainer', 'allowAsRoot', 'allowedTemplates', 'allowedContentTypes',
|
||||
'alias', 'description', 'thumbnail', 'name', 'id', 'icon', 'trashed',
|
||||
'key', 'parentId', 'alias', 'path', 'allowCultureVariant');
|
||||
'key', 'parentId', 'alias', 'path', 'allowCultureVariant', 'isElement');
|
||||
|
||||
//TODO: Map these
|
||||
saveModel.allowedTemplates = _.map(displayModel.allowedTemplates, function (t) { return t.alias; });
|
||||
@@ -262,7 +262,7 @@
|
||||
saveModel[props[m]] = startId.id;
|
||||
}
|
||||
|
||||
saveModel.parentId = -1;
|
||||
saveModel.parentId = -1;
|
||||
return saveModel;
|
||||
},
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
});
|
||||
saveModel.email = propEmail.value.trim();
|
||||
saveModel.username = propLogin.value.trim();
|
||||
|
||||
|
||||
saveModel.password = this.formatChangePasswordModel(propPass.value);
|
||||
|
||||
var selectedGroups = [];
|
||||
@@ -336,7 +336,7 @@
|
||||
|
||||
/** formats the display model used to display the media to the model used to save the media */
|
||||
formatMediaPostData: function (displayModel, action) {
|
||||
//NOTE: the display model inherits from the save model so we can in theory just post up the display model but
|
||||
//NOTE: the display model inherits from the save model so we can in theory just post up the display model but
|
||||
// we don't want to post all of the data as it is unecessary.
|
||||
var saveModel = {
|
||||
id: displayModel.id,
|
||||
@@ -354,7 +354,7 @@
|
||||
/** formats the display model used to display the content to the model used to save the content */
|
||||
formatContentPostData: function (displayModel, action) {
|
||||
|
||||
//NOTE: the display model inherits from the save model so we can in theory just post up the display model but
|
||||
//NOTE: the display model inherits from the save model so we can in theory just post up the display model but
|
||||
// we don't want to post all of the data as it is unecessary.
|
||||
var saveModel = {
|
||||
id: displayModel.id,
|
||||
@@ -379,7 +379,7 @@
|
||||
var propExpireDate = displayModel.removeDate;
|
||||
var propReleaseDate = displayModel.releaseDate;
|
||||
var propTemplate = displayModel.template;
|
||||
|
||||
|
||||
saveModel.expireDate = propExpireDate ? propExpireDate : null;
|
||||
saveModel.releaseDate = propReleaseDate ? propReleaseDate : null;
|
||||
saveModel.templateAlias = propTemplate ? propTemplate : null;
|
||||
@@ -389,8 +389,8 @@
|
||||
|
||||
/**
|
||||
* This formats the server GET response for a content display item
|
||||
* @param {} displayModel
|
||||
* @returns {}
|
||||
* @param {} displayModel
|
||||
* @returns {}
|
||||
*/
|
||||
formatContentGetData: function(displayModel) {
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
//now assign this same invariant property instance to the same index of the other variants property array
|
||||
for (var j = 1; j < displayModel.variants.length; j++) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* @param {navigationService} navigationService A reference to the navigationService
|
||||
*/
|
||||
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource) {
|
||||
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource) {
|
||||
|
||||
//this is used to trigger the tree to start loading once everything is ready
|
||||
var treeInitPromise = $q.defer();
|
||||
@@ -344,9 +344,6 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
|
||||
$scope.languages = languages;
|
||||
|
||||
if ($scope.languages.length > 1) {
|
||||
var defaultLang = _.find($scope.languages, function (l) {
|
||||
return l.isDefault;
|
||||
});
|
||||
//if there's already one set, check if it exists
|
||||
var currCulture = null;
|
||||
var mainCulture = $location.search().mculture;
|
||||
@@ -356,7 +353,20 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
|
||||
});
|
||||
}
|
||||
if (!currCulture) {
|
||||
$location.search("mculture", defaultLang ? defaultLang.culture : null);
|
||||
// no culture in the request, let's look for one in the cookie that's set when changing language
|
||||
var defaultCulture = $cookies.get("UMB_MCULTURE");
|
||||
if (!defaultCulture || !_.find($scope.languages, function (l) {
|
||||
return l.culture.toLowerCase() === defaultCulture.toLowerCase();
|
||||
})) {
|
||||
// no luck either, look for the default language
|
||||
var defaultLang = _.find($scope.languages, function (l) {
|
||||
return l.isDefault;
|
||||
});
|
||||
if (defaultLang) {
|
||||
defaultCulture = defaultLang.culture;
|
||||
}
|
||||
}
|
||||
$location.search("mculture", defaultCulture ? defaultCulture : null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,6 +401,10 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
|
||||
$scope.selectLanguage = function (language) {
|
||||
|
||||
$location.search("mculture", language.culture);
|
||||
// add the selected culture to a cookie so the user will log back into the same culture later on (cookie lifetime = one year)
|
||||
var expireDate = new Date();
|
||||
expireDate.setDate(expireDate.getDate() + 365);
|
||||
$cookies.put("UMB_MCULTURE", language.culture, {path: "/", expires: expireDate});
|
||||
|
||||
// close the language selector
|
||||
$scope.page.languageSelectorIsOpen = false;
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
@import "components/umb-file-dropzone.less";
|
||||
@import "components/umb-node-preview.less";
|
||||
@import "components/umb-mini-editor.less";
|
||||
@import "components/umb-property-file-upload.less";
|
||||
|
||||
@import "components/users/umb-user-cards.less";
|
||||
@import "components/users/umb-user-details.less";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
.umb-file-dropzone-directive{
|
||||
.umb-file-dropzone {
|
||||
|
||||
// drop zone
|
||||
// tall and small version - animate height
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-nested-content-property-container {
|
||||
position: relative;
|
||||
&:not(:last-child){
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-nested-content--not-supported {
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
.umb-property-file-upload {
|
||||
|
||||
.umb-upload-button-big {
|
||||
display: block;
|
||||
padding: 20px;
|
||||
opacity: 1;
|
||||
border: 1px dashed @gray-8;
|
||||
background: none;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
|
||||
&, &:hover {
|
||||
color: @gray-8;
|
||||
}
|
||||
|
||||
i.icon {
|
||||
font-size: 55px;
|
||||
line-height: 70px
|
||||
}
|
||||
|
||||
input {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
@checkered-background: url(../img/checkered-background.png);
|
||||
|
||||
//
|
||||
// Container styles
|
||||
// --------------------------------------------------
|
||||
@@ -353,7 +355,7 @@
|
||||
max-height:100%;
|
||||
margin:auto;
|
||||
display:block;
|
||||
background-image: url(../img/checkered-background.png);
|
||||
background-image: @checkered-background;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails li .trashed {
|
||||
@@ -576,12 +578,18 @@
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.gravity-container .viewport {
|
||||
max-width: 600px;
|
||||
}
|
||||
.gravity-container {
|
||||
border: 1px solid @gray-8;
|
||||
line-height: 0;
|
||||
|
||||
.gravity-container .viewport:hover {
|
||||
cursor: pointer;
|
||||
.viewport {
|
||||
max-width: 600px;
|
||||
background: @checkered-background;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.imagecropper {
|
||||
@@ -594,6 +602,10 @@
|
||||
float: left;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.viewport img {
|
||||
background: @checkered-background;
|
||||
}
|
||||
}
|
||||
|
||||
.imagecropper .umb-cropper__container {
|
||||
@@ -687,7 +699,7 @@
|
||||
//
|
||||
// folder-browser
|
||||
// --------------------------------------------------
|
||||
.umb-folderbrowser .add-link{
|
||||
.umb-folderbrowser .add-link {
|
||||
display: inline-block;
|
||||
height: 120px;
|
||||
width: 120px;
|
||||
@@ -696,17 +708,6 @@
|
||||
line-height: 120px
|
||||
}
|
||||
|
||||
.umb-upload-button-big:hover{color: @gray-8;}
|
||||
|
||||
.umb-upload-button-big {display: block}
|
||||
.umb-upload-button-big input {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// File upload
|
||||
// --------------------------------------------------
|
||||
@@ -724,6 +725,10 @@
|
||||
list-style: none;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 0;
|
||||
|
||||
img {
|
||||
background: @checkered-background;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-fileupload label {
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
@@ -138,4 +139,4 @@
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
@@ -68,4 +69,4 @@
|
||||
</form>
|
||||
|
||||
</umb-editor-view>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
@@ -75,4 +76,4 @@
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</form>
|
||||
</form>
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
<umb-button
|
||||
action="close()"
|
||||
button-style="link"
|
||||
shortcut="esc"
|
||||
label="Close"
|
||||
type="button">
|
||||
</umb-button>
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
|
||||
|
||||
@@ -193,6 +193,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
|
||||
@@ -209,4 +210,4 @@
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
@@ -101,4 +102,4 @@
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
@@ -51,4 +52,4 @@
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
@@ -97,4 +98,4 @@
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
@@ -87,4 +88,4 @@
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<!-- Icon for files -->
|
||||
<span class="umb-media-grid__item-file-icon" ng-if="!item.thumbnail && item.extension != 'svg'">
|
||||
<i class="umb-media-grid__item-icon {{item.icon}}"></i>
|
||||
<span>.{{item.extension}}</span>
|
||||
<span ng-if="item.extension">.{{item.extension}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div data-element="dropzone" class="umb-file-dropzone-directive">
|
||||
<div data-element="dropzone" class="umb-file-dropzone">
|
||||
|
||||
<ng-form name="uploadForm" umb-isolate-form>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<div>
|
||||
<div class="umb-property-file-upload">
|
||||
|
||||
<ng-form name="vm.fileUploadForm">
|
||||
|
||||
<div class="fileinput-button umb-upload-button-big"
|
||||
|
||||
@@ -1,26 +1,91 @@
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController",
|
||||
function ($scope, relationResource, contentResource, entityResource, navigationService, appState, treeService, localizationService) {
|
||||
function ($scope, relationResource, contentResource, entityResource, navigationService, appState, treeService, userService) {
|
||||
|
||||
$scope.source = _.clone($scope.currentNode);
|
||||
|
||||
$scope.error = null;
|
||||
$scope.success = false;
|
||||
$scope.error = null;
|
||||
$scope.loading = true;
|
||||
$scope.moving = false;
|
||||
$scope.success = false;
|
||||
|
||||
$scope.dialogTreeApi = {};
|
||||
$scope.searchInfo = {
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
}
|
||||
$scope.treeModel = {
|
||||
hideHeader: false
|
||||
}
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
$scope.treeModel.hideHeader = userData.startContentIds.length > 0 && userData.startContentIds.indexOf(-1) == -1;
|
||||
});
|
||||
|
||||
function nodeSelectHandler(args) {
|
||||
|
||||
if (args && args.event) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
}
|
||||
|
||||
if ($scope.target) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.target.selected = false;
|
||||
}
|
||||
|
||||
$scope.target = args.node;
|
||||
$scope.target.selected = true;
|
||||
|
||||
}
|
||||
|
||||
function nodeExpandedHandler(args) {
|
||||
// open mini list view for list views
|
||||
if (args.node.metaData.isContainer) {
|
||||
openMiniListView(args.node);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.hideSearch = function () {
|
||||
$scope.searchInfo.showSearch = false;
|
||||
$scope.searchInfo.results = [];
|
||||
}
|
||||
|
||||
// method to select a search result
|
||||
$scope.selectResult = function (evt, result) {
|
||||
result.selected = result.selected === true ? false : true;
|
||||
nodeSelectHandler(evt, { event: evt, node: result });
|
||||
};
|
||||
|
||||
//callback when there are search results
|
||||
$scope.onSearchResults = function (results) {
|
||||
$scope.searchInfo.results = results;
|
||||
$scope.searchInfo.showSearch = true;
|
||||
};
|
||||
|
||||
$scope.onTreeInit = function () {
|
||||
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
|
||||
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
|
||||
}
|
||||
|
||||
// Mini list view
|
||||
$scope.selectListViewNode = function (node) {
|
||||
node.selected = node.selected === true ? false : true;
|
||||
nodeSelectHandler({}, { node: node });
|
||||
};
|
||||
|
||||
$scope.closeMiniListView = function () {
|
||||
$scope.miniListView = undefined;
|
||||
};
|
||||
|
||||
function openMiniListView(node) {
|
||||
$scope.miniListView = node;
|
||||
}
|
||||
|
||||
relationResource.getByChildId($scope.source.id, "relateParentDocumentOnDelete").then(function (data) {
|
||||
$scope.loading = false;
|
||||
|
||||
if (!data.length) {
|
||||
localizationService.localizeMany(["recycleBin_itemCannotBeRestored", "recycleBin_noRestoreRelation"])
|
||||
.then(function(values) {
|
||||
$scope.success = false;
|
||||
$scope.error = {
|
||||
errorMsg: values[0],
|
||||
data: {
|
||||
Message: values[1]
|
||||
}
|
||||
}
|
||||
});
|
||||
$scope.moving = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,40 +95,32 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController"
|
||||
$scope.target = { id: -1, name: "Root" };
|
||||
|
||||
} else {
|
||||
$scope.loading = true;
|
||||
$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) {
|
||||
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;
|
||||
}
|
||||
$scope.target = data;
|
||||
|
||||
// make sure the target item isn't in the recycle bin
|
||||
if ($scope.target.path.indexOf("-20") !== -1) {
|
||||
$scope.moving = true;
|
||||
$scope.target = null;
|
||||
}
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
}
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
|
||||
$scope.restore = function () {
|
||||
$scope.loading = true;
|
||||
// this code was copied from `content.move.controller.js`
|
||||
|
||||
// this code was copied from `content.move.controller.js`
|
||||
contentResource.move({ parentId: $scope.target.id, id: $scope.source.id })
|
||||
.then(function (path) {
|
||||
|
||||
@@ -88,9 +145,8 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController"
|
||||
});
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,34 +1,93 @@
|
||||
<div ng-controller="Umbraco.Editors.Content.RestoreController">
|
||||
<div class="umb-dialog-body">
|
||||
<umb-pane>
|
||||
<div class="umb-dialog-body" ng-cloak>
|
||||
<umb-pane>
|
||||
<umb-load-indicator
|
||||
ng-show="loading">
|
||||
</umb-load-indicator>
|
||||
|
||||
<umb-load-indicator
|
||||
ng-show="loading">
|
||||
</umb-load-indicator>
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
<div><strong>{{error.errorMsg}}</strong></div>
|
||||
<div>{{error.data.Message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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 ng-show="success">
|
||||
<div class="alert alert-success">
|
||||
<strong>{{source.name}}</strong>
|
||||
<span ng-hide="moving"><localize key="recycleBin_wasRestored">was restored under</localize></span>
|
||||
<span ng-show="moving"><localize key="editdatatype_wasMoved">was moved underneath</localize></span>
|
||||
<strong>{{target.name}}</strong>
|
||||
</div>
|
||||
<button class="btn btn-primary" ng-click="close()">Ok</button>
|
||||
</div>
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
<div><strong>{{error.errorMsg}}</strong></div>
|
||||
<div>{{error.data.Message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-hide="moving || loading || success">
|
||||
|
||||
<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>
|
||||
<p class="abstract" ng-hide="error || success">
|
||||
<localize key="actions_restore">Restore</localize> <strong>{{source.name}}</strong> <localize key="general_under">under</localize> <strong>{{target.name}}</strong>?
|
||||
</p>
|
||||
|
||||
</umb-pane>
|
||||
</div>
|
||||
|
||||
<div ng-hide="!moving || loading || success">
|
||||
<div>
|
||||
<div class="alert alert-info">
|
||||
<div><strong><localize key="recycleBin_itemCannotBeRestored">Cannot automatically restore this item</localize></strong></div>
|
||||
<div><localize key="recycleBin_itemCannotBeRestoredHelpText">There is no location where this item can be automatically restored. You can move the item manually using the tree below.</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-hide="miniListView">
|
||||
<umb-tree-search-box
|
||||
hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="content">
|
||||
</umb-tree-search-box>
|
||||
|
||||
<br />
|
||||
|
||||
<umb-tree-search-results
|
||||
ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
|
||||
<div ng-hide="searchInfo.showSearch">
|
||||
<umb-tree
|
||||
section="content"
|
||||
hideheader="{{treeModel.hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
api="dialogTreeApi"
|
||||
on-init="onTreeInit()"
|
||||
enablelistviewexpand="true"
|
||||
enablecheckboxes="true">
|
||||
</umb-tree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<umb-mini-list-view
|
||||
ng-if="miniListView"
|
||||
node="miniListView"
|
||||
entity-type="Document"
|
||||
on-select="selectListViewNode(node)"
|
||||
on-close="closeMiniListView()">
|
||||
</umb-mini-list-view>
|
||||
|
||||
</div>
|
||||
|
||||
</umb-pane>
|
||||
</div>
|
||||
|
||||
<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 class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || moving || 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 class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || !moving || 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" ng-disabled="!target"><localize key="actions_move">Move</localize></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user