Merge origin/dev-v7.6 into deploy-219
This commit is contained in:
@@ -44,37 +44,37 @@
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\net462\businesslogic.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\net462\businesslogic.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\net462\cms.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\net462\cms.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\net462\controls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\net462\controls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\net462\interfaces.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\net462\interfaces.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\net462\log4net.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\net462\Microsoft.ApplicationBlocks.Data.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\net462\SQLCE4Umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.xml" target="lib\net462\SQLCE4Umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\net462\System.Data.SqlServerCe.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\net462\System.Data.SqlServerCe.Entity.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\net462\TidyNet.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\net462\Umbraco.Core.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\net462\Umbraco.Core.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\net462\umbraco.DataLayer.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\net462\umbraco.DataLayer.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\net462\umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\net462\umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\net462\umbraco.editorControls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\net462\umbraco.editorControls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\net462\umbraco.MacroEngines.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\net462\umbraco.MacroEngines.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\net462\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\net462\umbraco.providers.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net462\Umbraco.Web.UI.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\net462\Umbraco.Web.UI.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\net462\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\net462\UmbracoExamine.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\net45\businesslogic.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\net45\businesslogic.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\net45\cms.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\net45\cms.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\net45\controls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\net45\controls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\net45\interfaces.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\net45\interfaces.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\net45\log4net.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\net45\Microsoft.ApplicationBlocks.Data.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\net45\SQLCE4Umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.xml" target="lib\net45\SQLCE4Umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\net45\System.Data.SqlServerCe.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\net45\System.Data.SqlServerCe.Entity.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\net45\TidyNet.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\net45\Umbraco.Core.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\net45\Umbraco.Core.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\net45\umbraco.DataLayer.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\net45\umbraco.DataLayer.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\net45\umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\net45\umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\net45\umbraco.editorControls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\net45\umbraco.editorControls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\net45\umbraco.MacroEngines.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\net45\umbraco.MacroEngines.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\net45\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\net45\umbraco.providers.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net45\Umbraco.Web.UI.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\net45\Umbraco.Web.UI.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\net45\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\net45\UmbracoExamine.xml" />
|
||||
<file src="tools\install.core.ps1" target="tools\install.ps1" />
|
||||
|
||||
<!-- Added to be able to produce a symbols package -->
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.6.0
|
||||
alpha060
|
||||
alpha062
|
||||
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.6.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha060")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha062")]
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "alpha060"; } }
|
||||
public static string CurrentComment { get { return "alpha062"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -40,8 +40,8 @@ namespace Umbraco.Core
|
||||
|
||||
// forms
|
||||
public const string FormsForm = "forms-form";
|
||||
public const string FormsWorkflow = "forms-workflow";
|
||||
public const string FormsRecord = "forms-record";
|
||||
public const string FormsPreValue = "forms-prevalue";
|
||||
public const string FormsDataSource = "forms-datasource";
|
||||
|
||||
// string entity types
|
||||
|
||||
@@ -89,10 +89,10 @@ namespace Umbraco.Core
|
||||
return RelationType;
|
||||
case UmbracoObjectTypes.FormsForm:
|
||||
return FormsForm;
|
||||
case UmbracoObjectTypes.FormsWorkflow:
|
||||
return FormsWorkflow;
|
||||
case UmbracoObjectTypes.FormsRecord:
|
||||
return FormsRecord;
|
||||
case UmbracoObjectTypes.FormsPreValue:
|
||||
return FormsPreValue;
|
||||
case UmbracoObjectTypes.FormsDataSource:
|
||||
return FormsDataSource;
|
||||
}
|
||||
throw new NotSupportedException(string.Format("UmbracoObjectType \"{0}\" does not have a matching EntityType.", umbracoObjectType));
|
||||
}
|
||||
@@ -131,10 +131,10 @@ namespace Umbraco.Core
|
||||
return UmbracoObjectTypes.RelationType;
|
||||
case FormsForm:
|
||||
return UmbracoObjectTypes.FormsForm;
|
||||
case FormsWorkflow:
|
||||
return UmbracoObjectTypes.FormsWorkflow;
|
||||
case FormsRecord:
|
||||
return UmbracoObjectTypes.FormsRecord;
|
||||
case FormsPreValue:
|
||||
return UmbracoObjectTypes.FormsPreValue;
|
||||
case FormsDataSource:
|
||||
return UmbracoObjectTypes.FormsDataSource;
|
||||
}
|
||||
throw new NotSupportedException(
|
||||
string.Format("EntityType \"{0}\" does not have a matching UmbracoObjectType.", entityType));
|
||||
|
||||
@@ -174,24 +174,24 @@ namespace Umbraco.Core
|
||||
public static readonly Guid FormsFormGuid = new Guid(FormsForm);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Workflow.
|
||||
/// Guid for a Forms PreValue Source.
|
||||
/// </summary>
|
||||
public const string FormsWorkflow = "42D7BF9B-A362-4FEE-B45A-674D5C064B70";
|
||||
public const string FormsPreValue = "42D7BF9B-A362-4FEE-B45A-674D5C064B70";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Workflow.
|
||||
/// Guid for a Forms PreValue Source.
|
||||
/// </summary>
|
||||
public static readonly Guid FormsWorkflowGuid = new Guid(FormsWorkflow);
|
||||
public static readonly Guid FormsPreValueGuid = new Guid(FormsPreValue);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Record.
|
||||
/// Guid for a Forms DataSource.
|
||||
/// </summary>
|
||||
public const string FormsRecord = "CFED6CE4-9359-443E-9977-9956FEB1D867";
|
||||
public const string FormsDataSource = "CFED6CE4-9359-443E-9977-9956FEB1D867";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Record.
|
||||
/// Guid for a Forms DataSource.
|
||||
/// </summary>
|
||||
public static readonly Guid FormsRecordGuid = new Guid(FormsRecord);
|
||||
public static readonly Guid FormsDataSourceGuid = new Guid(FormsDataSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,11 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
get { return _packageMetaData; }
|
||||
}
|
||||
|
||||
public IEnumerable<TEntity> InstallationSummary
|
||||
{
|
||||
get { return EventObject; }
|
||||
}
|
||||
|
||||
public bool Equals(ImportPackageEventArgs<TEntity> other)
|
||||
{
|
||||
|
||||
31
src/Umbraco.Core/Events/UninstallPackageEventArgs.cs
Normal file
31
src/Umbraco.Core/Events/UninstallPackageEventArgs.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
internal class UninstallPackageEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
{
|
||||
private readonly MetaData _packageMetaData;
|
||||
|
||||
public UninstallPackageEventArgs(TEntity eventObject, bool canCancel)
|
||||
: base(new[] { eventObject }, canCancel)
|
||||
{
|
||||
}
|
||||
|
||||
public UninstallPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
|
||||
: base(new[] { eventObject })
|
||||
{
|
||||
_packageMetaData = packageMetaData;
|
||||
}
|
||||
|
||||
public MetaData PackageMetaData
|
||||
{
|
||||
get { return _packageMetaData; }
|
||||
}
|
||||
|
||||
public IEnumerable<TEntity> UninstallationSummary
|
||||
{
|
||||
get { return EventObject; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,11 @@ using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
@@ -351,7 +351,54 @@ namespace Umbraco.Core.IO
|
||||
writer.Write(contents);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given path is a full path including drive letter
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
// From: http://stackoverflow.com/a/35046453/5018
|
||||
internal static bool IsFullPath(this string path)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(path) == false
|
||||
&& path.IndexOfAny(Path.GetInvalidPathChars().ToArray()) == -1
|
||||
&& Path.IsPathRooted(path)
|
||||
&& Path.GetPathRoot(path).Equals(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) == false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get properly formatted relative path from an existing absolute or relative path
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
internal static string GetRelativePath(this string path)
|
||||
{
|
||||
if (path.IsFullPath())
|
||||
{
|
||||
var rootDirectory = GetRootDirectorySafe();
|
||||
var relativePath = path.ToLowerInvariant().Replace(rootDirectory.ToLowerInvariant(), string.Empty);
|
||||
path = relativePath;
|
||||
}
|
||||
|
||||
return path.EnsurePathIsApplicationRootPrefixed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that a path has `~/` as prefix
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
internal static string EnsurePathIsApplicationRootPrefixed(this string path)
|
||||
{
|
||||
if (path.StartsWith("~/"))
|
||||
return path;
|
||||
if (path.StartsWith("/") == false && path.StartsWith("\\") == false)
|
||||
path = string.Format("/{0}", path);
|
||||
if (path.StartsWith("~") == false)
|
||||
path = string.Format("~{0}", path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
[Column("LoginName")]
|
||||
[Length(1000)]
|
||||
[Constraint(Default = "''")]
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_cmsMember_LoginName")]
|
||||
public string LoginName { get; set; }
|
||||
|
||||
[Column("Password")]
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
|
||||
[Column("parentId")]
|
||||
[ForeignKey(typeof(NodeDto), Name = "FK_umbracoRelation_umbracoNode")]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelation_parentChildType", ForColumns = "parentId,childId,relType")]
|
||||
public int ParentId { get; set; }
|
||||
|
||||
[Column("childId")]
|
||||
|
||||
@@ -29,11 +29,13 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
public Guid ChildObjectType { get; set; }
|
||||
|
||||
[Column("name")]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelationType_name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("alias")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(100)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelationType_alias")]
|
||||
public string Alias { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -153,17 +153,17 @@ namespace Umbraco.Core.Models
|
||||
FormsForm,
|
||||
|
||||
/// <summary>
|
||||
/// Forms Workflow
|
||||
/// Forms PreValue
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsWorkflow)]
|
||||
[FriendlyName("Workflow")]
|
||||
FormsWorkflow,
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsPreValue)]
|
||||
[FriendlyName("PreValue")]
|
||||
FormsPreValue,
|
||||
|
||||
/// <summary>
|
||||
/// Forms Record
|
||||
/// Forms DataSource
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsRecord)]
|
||||
[FriendlyName("Record")]
|
||||
FormsRecord
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsDataSource)]
|
||||
[FriendlyName("DataSource")]
|
||||
FormsDataSource
|
||||
}
|
||||
}
|
||||
42
src/Umbraco.Core/Packaging/Models/UninstallationSummary.cs
Normal file
42
src/Umbraco.Core/Packaging/Models/UninstallationSummary.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Packaging.Models
|
||||
{
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class UninstallationSummary
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public IEnumerable<IDataTypeDefinition> DataTypesUninstalled { get; set; }
|
||||
public IEnumerable<ILanguage> LanguagesUninstalled { get; set; }
|
||||
public IEnumerable<IDictionaryItem> DictionaryItemsUninstalled { get; set; }
|
||||
public IEnumerable<IMacro> MacrosUninstalled { get; set; }
|
||||
public IEnumerable<string> FilesUninstalled { get; set; }
|
||||
public IEnumerable<ITemplate> TemplatesUninstalled { get; set; }
|
||||
public IEnumerable<IContentType> ContentTypesUninstalled { get; set; }
|
||||
public IEnumerable<IFile> StylesheetsUninstalled { get; set; }
|
||||
public IEnumerable<IContent> ContentUninstalled { get; set; }
|
||||
public bool PackageUninstalled { get; set; }
|
||||
}
|
||||
|
||||
internal static class UninstallationSummaryExtentions
|
||||
{
|
||||
public static UninstallationSummary InitEmpty(this UninstallationSummary summary)
|
||||
{
|
||||
summary.ContentUninstalled = new List<IContent>();
|
||||
summary.ContentTypesUninstalled = new List<IContentType>();
|
||||
summary.DataTypesUninstalled = new List<IDataTypeDefinition>();
|
||||
summary.DictionaryItemsUninstalled = new List<IDictionaryItem>();
|
||||
summary.FilesUninstalled = new List<string>();
|
||||
summary.LanguagesUninstalled = new List<ILanguage>();
|
||||
summary.MacrosUninstalled = new List<IMacro>();
|
||||
summary.MetaData = new MetaData();
|
||||
summary.TemplatesUninstalled = new List<ITemplate>();
|
||||
summary.PackageUninstalled = false;
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,20 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
#region Implementation of IEntityFactory<IContent,DocumentDto>
|
||||
|
||||
public static IContent BuildEntity(DocumentDto dto, IContentType contentType)
|
||||
/// <summary>
|
||||
/// Builds a IContent item from the dto(s) and content type
|
||||
/// </summary>
|
||||
/// <param name="dto">
|
||||
/// This DTO can contain all of the information to build an IContent item, however in cases where multiple entities are being built,
|
||||
/// a separate <see cref="DocumentPublishedReadOnlyDto"/> publishedDto entity will be supplied in place of the <see cref="DocumentDto"/>'s own
|
||||
/// ResultColumn DocumentPublishedReadOnlyDto
|
||||
/// </param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="publishedDto">
|
||||
/// When querying for multiple content items the main DTO will not contain the ResultColumn DocumentPublishedReadOnlyDto and a separate publishedDto instance will be supplied
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public static IContent BuildEntity(DocumentDto dto, IContentType contentType, DocumentPublishedReadOnlyDto publishedDto = null)
|
||||
{
|
||||
var content = new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, contentType);
|
||||
|
||||
@@ -52,8 +65,13 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
content.ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?)null;
|
||||
content.ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?)null;
|
||||
content.Version = dto.ContentVersionDto.VersionId;
|
||||
|
||||
content.PublishedState = dto.Published ? PublishedState.Published : PublishedState.Unpublished;
|
||||
content.PublishedVersionGuid = dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId;
|
||||
|
||||
//Check if the publishedDto has been supplied, if not the use the dto's own DocumentPublishedReadOnlyDto value
|
||||
content.PublishedVersionGuid = publishedDto == null
|
||||
? (dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId)
|
||||
: publishedDto.VersionId;
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
{
|
||||
[Migration("7.6.0", 0, Constants.System.UmbracoMigrationName)]
|
||||
public class AddIndexToCmsMemberLoginName : MigrationBase
|
||||
{
|
||||
public AddIndexToCmsMemberLoginName(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsMember_LoginName")) == false)
|
||||
{
|
||||
Create.Index("IX_cmsMember_LoginName").OnTable("cmsMember")
|
||||
.OnColumn("LoginName")
|
||||
.Ascending()
|
||||
.WithOptions()
|
||||
.NonClustered();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
Delete.Index("IX_cmsMember_LoginName").OnTable("cmsMember");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodePath")) == false)
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
{
|
||||
[Migration("7.6.0", 0, Constants.System.UmbracoMigrationName)]
|
||||
public class AddIndexesToUmbracoRelationTables : MigrationBase
|
||||
{
|
||||
public AddIndexesToUmbracoRelationTables(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database).ToArray();
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelation_parentChildType")) == false)
|
||||
{
|
||||
//This will remove any corrupt/duplicate data in the relation table before the index is applied
|
||||
//Ensure this executes in a defered block which will be done inside of the migration transaction
|
||||
this.Execute.Code(database =>
|
||||
{
|
||||
//We need to check if this index has corrupted data and then clear that data
|
||||
var duplicates = database.Fetch<dynamic>("SELECT parentId,childId,relType FROM umbracoRelation GROUP BY parentId,childId,relType HAVING COUNT(*) > 1");
|
||||
if (duplicates.Count > 0)
|
||||
{
|
||||
//need to fix this there cannot be duplicates so we'll take the latest entries, it's really not going to matter though
|
||||
foreach (var duplicate in duplicates)
|
||||
{
|
||||
var ids = database.Fetch<int>("SELECT id FROM umbracoRelation WHERE parentId=@parentId AND childId=@childId AND relType=@relType ORDER BY datetime DESC",
|
||||
new { parentId = duplicate.parentId, childId = duplicate.childId, relType = duplicate.relType });
|
||||
|
||||
if (ids.Count == 1)
|
||||
{
|
||||
//this is just a safety check, this should absolutely never happen
|
||||
throw new InvalidOperationException("Duplicates were detected but could not be discovered");
|
||||
}
|
||||
|
||||
//delete the others
|
||||
ids = ids.Skip(0).ToList();
|
||||
|
||||
//iterate in groups of 2000 to avoid the max sql parameter limit
|
||||
foreach (var idGroup in ids.InGroupsOf(2000))
|
||||
{
|
||||
database.Execute("DELETE FROM umbracoRelation WHERE id IN (@ids)", new { ids = idGroup });
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
//unique index to prevent duplicates - and for better perf
|
||||
Create.Index("IX_umbracoRelation_parentChildType").OnTable("umbracoRelation")
|
||||
.OnColumn("parentId").Ascending()
|
||||
.OnColumn("childId").Ascending()
|
||||
.OnColumn("relType").Ascending()
|
||||
.WithOptions()
|
||||
.Unique();
|
||||
}
|
||||
|
||||
//need indexes on alias and name for relation type since these are queried against
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelationType_alias")) == false)
|
||||
{
|
||||
Create.Index("IX_umbracoRelationType_alias").OnTable("umbracoRelationType")
|
||||
.OnColumn("alias")
|
||||
.Ascending()
|
||||
.WithOptions()
|
||||
.NonClustered();
|
||||
}
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelationType_name")) == false)
|
||||
{
|
||||
Create.Index("IX_umbracoRelationType_name").OnTable("umbracoRelationType")
|
||||
.OnColumn("name")
|
||||
.Ascending()
|
||||
.WithOptions()
|
||||
.NonClustered();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
Delete.Index("IX_umbracoNodePath").OnTable("umbracoNode");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,30 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal enum BaseQueryType
|
||||
{
|
||||
Full,
|
||||
/// <summary>
|
||||
/// A query to return all information for a single item
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In some cases this will be the same as <see cref="FullMultiple"/>
|
||||
/// </remarks>
|
||||
FullSingle,
|
||||
|
||||
/// <summary>
|
||||
/// A query to return all information for multiple items
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In some cases this will be the same as <see cref="FullSingle"/>
|
||||
/// </remarks>
|
||||
FullMultiple,
|
||||
|
||||
/// <summary>
|
||||
/// A query to return the ids for items
|
||||
/// </summary>
|
||||
Ids,
|
||||
|
||||
/// <summary>
|
||||
/// A query to return the count for items
|
||||
/// </summary>
|
||||
Count
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
@@ -53,7 +54,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IContent PerformGet(int id)
|
||||
{
|
||||
var sql = GetBaseQuery(false)
|
||||
var sql = GetBaseQuery(BaseQueryType.FullSingle)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.Where<DocumentDto>(x => x.Newest, SqlSyntax)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
@@ -81,15 +82,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return s;
|
||||
};
|
||||
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.FullMultiple);
|
||||
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
|
||||
return ProcessQuery(translate(sqlBaseFull), translate(sqlBaseIds));
|
||||
return ProcessQuery(translate(sqlBaseFull), new PagingSqlQuery(translate(sqlBaseIds)));
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContent> PerformGetByQuery(IQuery<IContent> query)
|
||||
{
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.FullMultiple);
|
||||
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
|
||||
Func<SqlTranslator<IContent>, Sql> translate = (translator) =>
|
||||
@@ -103,13 +104,25 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var translatorFull = new SqlTranslator<IContent>(sqlBaseFull, query);
|
||||
var translatorIds = new SqlTranslator<IContent>(sqlBaseIds, query);
|
||||
|
||||
return ProcessQuery(translate(translatorFull), translate(translatorIds));
|
||||
return ProcessQuery(translate(translatorFull), new PagingSqlQuery(translate(translatorIds)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of PetaPocoRepositoryBase<IContent>
|
||||
|
||||
/// <summary>
|
||||
/// Returns the base query to return Content
|
||||
/// </summary>
|
||||
/// <param name="queryType"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Content queries will differ depending on what needs to be returned:
|
||||
/// * FullSingle: When querying for a single document, this will include the Outer join to fetch the content item's published version info
|
||||
/// * FullMultiple: When querying for multiple documents, this will exclude the Outer join to fetch the content item's published version info - this info would need to be fetched separately
|
||||
/// * Ids: This would essentially be the same as FullMultiple however the columns specified will only return the Ids for the documents
|
||||
/// * Count: A query to return the count for documents
|
||||
/// </remarks>
|
||||
protected override Sql GetBaseQuery(BaseQueryType queryType)
|
||||
{
|
||||
var sql = new Sql();
|
||||
@@ -122,14 +135,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
|
||||
|
||||
if (queryType == BaseQueryType.Full)
|
||||
if (queryType == BaseQueryType.FullSingle)
|
||||
{
|
||||
//The only reason we apply this left outer join is to be able to pull back the DocumentPublishedReadOnlyDto
|
||||
//information with the entire data set, so basically this will get both the latest document and also it's published
|
||||
//version if it has one. When performing a count or when just retrieving Ids like in paging, this is unecessary
|
||||
//version if it has one. When performing a count or when retrieving Ids like in paging, this is unecessary
|
||||
//and causes huge performance overhead for the SQL server, especially when sorting the result.
|
||||
//To fix this perf overhead we'd need another index on :
|
||||
// CREATE NON CLUSTERED INDEX ON cmsDocument.node + cmsDocument.published
|
||||
//We also don't include this outer join when querying for multiple entities since it is much faster to fetch this information
|
||||
//in a separate query. For a single entity this is ok.
|
||||
|
||||
var sqlx = string.Format("LEFT OUTER JOIN {0} {1} ON ({1}.{2}={0}.{2} AND {1}.{3}=1)",
|
||||
SqlSyntax.GetQuotedTableName("cmsDocument"),
|
||||
@@ -151,7 +164,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.FullSingle);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
@@ -222,10 +235,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
while (true)
|
||||
{
|
||||
// get the next group of nodes
|
||||
var sqlFull = translate(baseId, GetBaseQuery(BaseQueryType.Full));
|
||||
var sqlFull = translate(baseId, GetBaseQuery(BaseQueryType.FullMultiple));
|
||||
var sqlIds = translate(baseId, GetBaseQuery(BaseQueryType.Ids));
|
||||
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(sqlFull, groupSize), SqlSyntax.SelectTop(sqlIds, groupSize))
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(sqlFull, groupSize), new PagingSqlQuery(SqlSyntax.SelectTop(sqlIds, groupSize)))
|
||||
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
|
||||
.ToList();
|
||||
|
||||
@@ -245,7 +258,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Logger.Error<MediaRepository>("Could not rebuild XML for nodeId=" + xmlItem.NodeId, e);
|
||||
}
|
||||
}
|
||||
baseId = xmlItems.Last().NodeId;
|
||||
baseId = xmlItems[xmlItems.Count - 1].NodeId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,15 +270,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
};
|
||||
|
||||
var sqlFull = translate(GetBaseQuery(BaseQueryType.Full));
|
||||
var sqlFull = translate(GetBaseQuery(BaseQueryType.FullMultiple));
|
||||
var sqlIds = translate(GetBaseQuery(BaseQueryType.Ids));
|
||||
|
||||
return ProcessQuery(sqlFull, sqlIds, true);
|
||||
return ProcessQuery(sqlFull, new PagingSqlQuery(sqlIds), true);
|
||||
}
|
||||
|
||||
public override IContent GetByVersion(Guid versionId)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
var sql = GetBaseQuery(BaseQueryType.FullSingle);
|
||||
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
|
||||
@@ -675,12 +688,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
// ORDER BY substring(path, 1, len(path) - charindex(',', reverse(path))), sortOrder
|
||||
// but that's probably an overkill - sorting by level,sortOrder should be enough
|
||||
|
||||
var sqlFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var sqlFull = GetBaseQuery(BaseQueryType.FullMultiple);
|
||||
var translatorFull = new SqlTranslator<IContent>(sqlFull, query);
|
||||
var sqlIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
var translatorIds = new SqlTranslator<IContent>(sqlIds, query);
|
||||
|
||||
return ProcessQuery(translate(translatorFull), translate(translatorIds), true);
|
||||
return ProcessQuery(translate(translatorFull), new PagingSqlQuery(translate(translatorIds)), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -860,7 +873,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
|
||||
return GetPagedResultsByQuery<DocumentDto>(query, pageIndex, pageSize, out totalRecords,
|
||||
new Tuple<string, string>("cmsDocument", "nodeId"),
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull, sqlIds), orderBy, orderDirection, orderBySystemField,
|
||||
(sqlFull, pagingSqlQuery) => ProcessQuery(sqlFull, pagingSqlQuery), orderBy, orderDirection, orderBySystemField,
|
||||
filterCallback);
|
||||
|
||||
}
|
||||
@@ -890,23 +903,58 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
|
||||
return base.GetDatabaseFieldNameForOrderBy(orderBy);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is the underlying method that processes most queries for this repository
|
||||
/// </summary>
|
||||
/// <param name="sqlFull">
|
||||
/// The full SQL with the outer join to return all data required to create an IContent
|
||||
/// The FullMultiple SQL without the outer join to return all data required to create an IContent excluding it's published state data which this will query separately
|
||||
/// </param>
|
||||
/// <param name="sqlIds">
|
||||
/// <param name="pagingSqlQuery">
|
||||
/// The Id SQL without the outer join to just return all document ids - used to process the properties for the content item
|
||||
/// </param>
|
||||
/// <param name="withCache"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, Sql sqlIds, bool withCache = false)
|
||||
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false)
|
||||
{
|
||||
// fetch returns a list so it's ok to iterate it in this method
|
||||
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sqlFull);
|
||||
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sqlFull);
|
||||
if (dtos.Count == 0) return Enumerable.Empty<IContent>();
|
||||
|
||||
//Go and get all of the published version data separately for this data, this is because when we are querying
|
||||
//for multiple content items we don't include the outer join to fetch this data in the same query because
|
||||
//it is insanely slow. Instead we just fetch the published version data separately in one query.
|
||||
|
||||
//we need to parse the original SQL statement and reduce the columns to just cmsDocument.nodeId so that we can use
|
||||
// the statement to go get the published data for all of the items by using an inner join
|
||||
var parsedOriginalSql = "SELECT cmsDocument.nodeId " + sqlFull.SQL.Substring(sqlFull.SQL.IndexOf("FROM", StringComparison.Ordinal));
|
||||
//now remove everything from an Orderby clause and beyond
|
||||
if (parsedOriginalSql.InvariantContains("ORDER BY "))
|
||||
{
|
||||
parsedOriginalSql = parsedOriginalSql.Substring(0, parsedOriginalSql.LastIndexOf("ORDER BY ", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
var publishedSql = new Sql(@"SELECT *
|
||||
FROM cmsDocument AS doc2
|
||||
INNER JOIN
|
||||
(" + parsedOriginalSql + @") as docData
|
||||
ON doc2.nodeId = docData.nodeId
|
||||
WHERE doc2.published = 1
|
||||
ORDER BY doc2.nodeId
|
||||
", sqlFull.Arguments);
|
||||
|
||||
//go and get the published version data, we do a Query here and not a Fetch so we are
|
||||
//not allocating a whole list to memory just to allocate another list in memory since
|
||||
//we are assigning this data to a keyed collection for fast lookup below
|
||||
var publishedData = Database.Query<DocumentPublishedReadOnlyDto>(publishedSql);
|
||||
var publishedDataCollection = new DocumentPublishedReadOnlyDtoCollection();
|
||||
foreach (var publishedDto in publishedData)
|
||||
{
|
||||
//double check that there's no corrupt db data, there should only be a single published item
|
||||
if (publishedDataCollection.Contains(publishedDto.NodeId) == false)
|
||||
publishedDataCollection.Add(publishedDto);
|
||||
}
|
||||
|
||||
|
||||
var content = new IContent[dtos.Count];
|
||||
var defs = new List<DocumentDefinition>();
|
||||
@@ -920,6 +968,8 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
for (var i = 0; i < dtos.Count; i++)
|
||||
{
|
||||
var dto = dtos[i];
|
||||
DocumentPublishedReadOnlyDto publishedDto;
|
||||
publishedDataCollection.TryGetValue(dto.NodeId, out publishedDto);
|
||||
|
||||
// if the cache contains the published version, use it
|
||||
if (withCache)
|
||||
@@ -947,7 +997,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
contentTypes[dto.ContentVersionDto.ContentDto.ContentTypeId] = contentType;
|
||||
}
|
||||
|
||||
content[i] = ContentFactory.BuildEntity(dto, contentType);
|
||||
content[i] = ContentFactory.BuildEntity(dto, contentType, publishedDto);
|
||||
|
||||
// need template
|
||||
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
|
||||
@@ -968,7 +1018,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
// load all properties for all documents from database in 1 query
|
||||
var propertyData = GetPropertyCollection(sqlIds, defs);
|
||||
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
|
||||
|
||||
// assign
|
||||
var dtoIndex = 0;
|
||||
@@ -1056,7 +1106,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
|
||||
return currentName;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dispose disposable properties
|
||||
/// </summary>
|
||||
@@ -1071,5 +1121,26 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
_contentPreviewRepository.Dispose();
|
||||
_contentXmlRepository.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A keyed collection for fast lookup when retrieving a separate list of published version data
|
||||
/// </summary>
|
||||
private class DocumentPublishedReadOnlyDtoCollection : KeyedCollection<int, DocumentPublishedReadOnlyDto>
|
||||
{
|
||||
protected override int GetKeyForItem(DocumentPublishedReadOnlyDto item)
|
||||
{
|
||||
return item.NodeId;
|
||||
}
|
||||
|
||||
public bool TryGetValue(int key, out DocumentPublishedReadOnlyDto val)
|
||||
{
|
||||
if (Dictionary == null)
|
||||
{
|
||||
val = null;
|
||||
return false;
|
||||
}
|
||||
return Dictionary.TryGetValue(key, out val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
sql.Where("umbracoNode.id in (@ids)", new { ids = ids });
|
||||
}
|
||||
|
||||
return ProcessQuery(sql);
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMedia> PerformGetByQuery(IQuery<IMedia> query)
|
||||
@@ -78,7 +78,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
|
||||
return ProcessQuery(sql);
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -100,7 +100,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.FullSingle);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
@@ -143,13 +143,24 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
return ProcessQuery(sql, true);
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql), true);
|
||||
}
|
||||
|
||||
private IEnumerable<IMedia> ProcessQuery(Sql sql, bool withCache = false)
|
||||
/// <summary>
|
||||
/// This is the underlying method that processes most queries for this repository
|
||||
/// </summary>
|
||||
/// <param name="sqlFull">
|
||||
/// The full SQL to select all media data
|
||||
/// </param>
|
||||
/// <param name="pagingSqlQuery">
|
||||
/// The Id SQL to just return all media ids - used to process the properties for the media item
|
||||
/// </param>
|
||||
/// <param name="withCache"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IMedia> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false)
|
||||
{
|
||||
// fetch returns a list so it's ok to iterate it in this method
|
||||
var dtos = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql);
|
||||
var dtos = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sqlFull);
|
||||
var content = new IMedia[dtos.Count];
|
||||
var defs = new List<DocumentDefinition>();
|
||||
|
||||
@@ -200,7 +211,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
// load all properties for all documents from database in 1 query
|
||||
var propertyData = GetPropertyCollection(sql, defs);
|
||||
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
|
||||
|
||||
// assign
|
||||
var dtoIndex = 0;
|
||||
@@ -257,7 +268,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
query = query
|
||||
.Where<NodeDto>(x => x.NodeId > baseId, SqlSyntax)
|
||||
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(query, groupSize))
|
||||
var sql = SqlSyntax.SelectTop(query, groupSize);
|
||||
var xmlItems = ProcessQuery(sql, new PagingSqlQuery(sql))
|
||||
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
|
||||
.ToList();
|
||||
|
||||
@@ -505,7 +517,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return GetPagedResultsByQuery<ContentVersionDto>(query, pageIndex, pageSize, out totalRecords,
|
||||
new Tuple<string, string>("cmsContentVersion", "contentId"),
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull), orderBy, orderDirection, orderBySystemField,
|
||||
(sqlFull, pagingSqlQuery) => ProcessQuery(sqlFull, pagingSqlQuery), orderBy, orderDirection, orderBySystemField,
|
||||
filterCallback);
|
||||
|
||||
}
|
||||
@@ -513,7 +525,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Private method to create a media object from a ContentDto
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="docSql"></param>
|
||||
/// <returns></returns>
|
||||
@@ -525,7 +537,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
var docDef = new DocumentDefinition(dto.NodeId, versionId, media.UpdateDate, media.CreateDate, contentType);
|
||||
|
||||
var properties = GetPropertyCollection(docSql, new[] { docDef });
|
||||
var properties = GetPropertyCollection(new PagingSqlQuery(docSql), new[] { docDef });
|
||||
|
||||
media.Properties = properties[dto.NodeId];
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
sql.Where("umbracoNode.id in (@ids)", new { ids = ids });
|
||||
}
|
||||
|
||||
return ProcessQuery(sql);
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
baseQuery.Append(new Sql("WHERE umbracoNode.id IN (" + sql.SQL + ")", sql.Arguments))
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
|
||||
return ProcessQuery(baseQuery);
|
||||
return ProcessQuery(baseQuery, new PagingSqlQuery(baseQuery));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -98,7 +98,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
|
||||
return ProcessQuery(sql);
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -129,7 +129,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
|
||||
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.FullSingle);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
@@ -385,7 +385,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
return ProcessQuery(sql, true);
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql), true);
|
||||
}
|
||||
|
||||
public void RebuildXmlStructures(Func<IMember, XElement> serializer, int groupSize = 200, IEnumerable<int> contentTypeIds = null)
|
||||
@@ -408,7 +408,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
query = query
|
||||
.Where<NodeDto>(x => x.NodeId > baseId)
|
||||
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(query, groupSize))
|
||||
var sql = SqlSyntax.SelectTop(query, groupSize);
|
||||
var xmlItems = ProcessQuery(sql, new PagingSqlQuery(sql))
|
||||
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
|
||||
.ToList();
|
||||
|
||||
@@ -449,7 +450,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var factory = new MemberFactory(memberType, NodeObjectTypeId, dto.NodeId);
|
||||
var media = factory.BuildEntity(dto);
|
||||
|
||||
var properties = GetPropertyCollection(sql, new[] { new DocumentDefinition(dto.NodeId, dto.ContentVersionDto.VersionId, media.UpdateDate, media.CreateDate, memberType) });
|
||||
var properties = GetPropertyCollection(new PagingSqlQuery(sql), new[] { new DocumentDefinition(dto.NodeId, dto.ContentVersionDto.VersionId, media.UpdateDate, media.CreateDate, memberType) });
|
||||
|
||||
media.Properties = properties[dto.NodeId];
|
||||
|
||||
@@ -540,7 +541,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
|
||||
return ProcessQuery(sql);
|
||||
return ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
|
||||
}
|
||||
|
||||
@@ -601,7 +602,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return GetPagedResultsByQuery<MemberDto>(query, pageIndex, pageSize, out totalRecords,
|
||||
new Tuple<string, string>("cmsMember", "nodeId"),
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull), orderBy, orderDirection, orderBySystemField,
|
||||
(sqlFull, sqlIds) => ProcessQuery(sqlFull, sqlIds), orderBy, orderDirection, orderBySystemField,
|
||||
filterCallback);
|
||||
}
|
||||
|
||||
@@ -641,10 +642,21 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return base.GetEntityPropertyNameForOrderBy(orderBy);
|
||||
}
|
||||
|
||||
private IEnumerable<IMember> ProcessQuery(Sql sql, bool withCache = false)
|
||||
/// <summary>
|
||||
/// This is the underlying method that processes most queries for this repository
|
||||
/// </summary>
|
||||
/// <param name="sqlFull">
|
||||
/// The full SQL to select all member data
|
||||
/// </param>
|
||||
/// <param name="pagingSqlQuery">
|
||||
/// The Id SQL to just return all member ids - used to process the properties for the member item
|
||||
/// </param>
|
||||
/// <param name="withCache"></param>
|
||||
/// <returns></returns>
|
||||
private IEnumerable<IMember> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false)
|
||||
{
|
||||
// fetch returns a list so it's ok to iterate it in this method
|
||||
var dtos = Database.Fetch<MemberDto, ContentVersionDto, ContentDto, NodeDto>(sql);
|
||||
var dtos = Database.Fetch<MemberDto, ContentVersionDto, ContentDto, NodeDto>(sqlFull);
|
||||
|
||||
var content = new IMember[dtos.Count];
|
||||
var defs = new List<DocumentDefinition>();
|
||||
@@ -681,7 +693,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
// load all properties for all documents from database in 1 query
|
||||
var propertyData = GetPropertyCollection(sql, defs);
|
||||
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
|
||||
|
||||
// assign
|
||||
var dtoIndex = 0;
|
||||
|
||||
@@ -432,7 +432,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <exception cref="System.ArgumentNullException">orderBy</exception>
|
||||
protected IEnumerable<TEntity> GetPagedResultsByQuery<TDto>(IQuery<TEntity> query, long pageIndex, int pageSize, out long totalRecords,
|
||||
Tuple<string, string> nodeIdSelect,
|
||||
Func<Sql, Sql, IEnumerable<TEntity>> processQuery,
|
||||
Func<Sql, PagingSqlQuery<TDto>, IEnumerable<TEntity>> processQuery,
|
||||
string orderBy,
|
||||
Direction orderDirection,
|
||||
bool orderBySystemField,
|
||||
@@ -443,7 +443,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
// Get base query for returning IDs
|
||||
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
|
||||
// Get base query for returning all data
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
|
||||
var sqlBaseFull = GetBaseQuery(BaseQueryType.FullMultiple);
|
||||
|
||||
if (query == null) query = new Query<TEntity>();
|
||||
var translatorIds = new SqlTranslator<TEntity>(sqlBaseIds, query);
|
||||
@@ -466,7 +466,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
// the pageResult, then the GetAll will actually return ALL records in the db.
|
||||
if (pagedResult.Items.Any())
|
||||
{
|
||||
//Crete the inner paged query that was used above to get the paged result, we'll use that as the inner sub query
|
||||
//Create the inner paged query that was used above to get the paged result, we'll use that as the inner sub query
|
||||
var args = sqlNodeIdsWithSort.Arguments;
|
||||
string sqlStringCount, sqlStringPage;
|
||||
Database.BuildPageQueries<TDto>(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage);
|
||||
@@ -486,8 +486,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var fullQuery = GetSortedSqlForPagedResults(
|
||||
GetFilteredSqlForPagedResults(fullQueryWithPagedInnerJoin, defaultFilter),
|
||||
orderDirection, orderBy, orderBySystemField, nodeIdSelect);
|
||||
|
||||
return processQuery(fullQuery, sqlNodeIdsWithSort);
|
||||
|
||||
return processQuery(fullQuery, new PagingSqlQuery<TDto>(Database, sqlNodeIdsWithSort, pageIndex, pageSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -497,18 +497,47 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property collection for a non-paged query
|
||||
/// </summary>
|
||||
/// <param name="sql"></param>
|
||||
/// <param name="documentDefs"></param>
|
||||
/// <returns></returns>
|
||||
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
|
||||
Sql docSql,
|
||||
Sql sql,
|
||||
IReadOnlyCollection<DocumentDefinition> documentDefs)
|
||||
{
|
||||
return GetPropertyCollection(new PagingSqlQuery(sql), documentDefs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property collection for a query
|
||||
/// </summary>
|
||||
/// <param name="pagingSqlQuery"></param>
|
||||
/// <param name="documentDefs"></param>
|
||||
/// <returns></returns>
|
||||
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
|
||||
PagingSqlQuery pagingSqlQuery,
|
||||
IReadOnlyCollection<DocumentDefinition> documentDefs)
|
||||
{
|
||||
if (documentDefs.Count == 0) return new Dictionary<int, PropertyCollection>();
|
||||
|
||||
//initialize to the query passed in
|
||||
var docSql = pagingSqlQuery.PrePagedSql;
|
||||
|
||||
//we need to parse the original SQL statement and reduce the columns to just cmsContent.nodeId, cmsContentVersion.VersionId so that we can use
|
||||
// the statement to go get the property data for all of the items by using an inner join
|
||||
var parsedOriginalSql = "SELECT {0} " + docSql.SQL.Substring(docSql.SQL.IndexOf("FROM", StringComparison.Ordinal));
|
||||
//now remove everything from an Orderby clause and beyond
|
||||
if (parsedOriginalSql.InvariantContains("ORDER BY "))
|
||||
|
||||
if (pagingSqlQuery.HasPaging)
|
||||
{
|
||||
//if this is a paged query, build the paged query with the custom column substitution, then re-assign
|
||||
docSql = pagingSqlQuery.BuildPagedQuery("{0}");
|
||||
parsedOriginalSql = docSql.SQL;
|
||||
}
|
||||
else if (parsedOriginalSql.InvariantContains("ORDER BY "))
|
||||
{
|
||||
//now remove everything from an Orderby clause and beyond if this is unpaged data
|
||||
parsedOriginalSql = parsedOriginalSql.Substring(0, parsedOriginalSql.LastIndexOf("ORDER BY ", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
@@ -525,7 +554,7 @@ WHERE EXISTS(
|
||||
INNER JOIN cmsPropertyType
|
||||
ON b.datatypeNodeId = cmsPropertyType.dataTypeId
|
||||
INNER JOIN
|
||||
(" + string.Format(parsedOriginalSql, "DISTINCT cmsContent.contentType") + @") as docData
|
||||
(" + string.Format(parsedOriginalSql, "cmsContent.contentType") + @") as docData
|
||||
ON cmsPropertyType.contentTypeId = docData.contentType
|
||||
WHERE a.id = b.id)", docSql.Arguments);
|
||||
|
||||
@@ -646,28 +675,7 @@ ORDER BY contentNodeId, propertytypeid
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public class DocumentDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
|
||||
/// </summary>
|
||||
public DocumentDefinition(int id, Guid version, DateTime versionDate, DateTime createDate, IContentTypeComposition composition)
|
||||
{
|
||||
Id = id;
|
||||
Version = version;
|
||||
VersionDate = versionDate;
|
||||
CreateDate = createDate;
|
||||
Composition = composition;
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public Guid Version { get; set; }
|
||||
public DateTime VersionDate { get; set; }
|
||||
public DateTime CreateDate { get; set; }
|
||||
public IContentTypeComposition Composition { get; set; }
|
||||
}
|
||||
|
||||
|
||||
protected virtual string GetDatabaseFieldNameForOrderBy(string orderBy)
|
||||
{
|
||||
// Translate the passed order by field (which were originally defined for in-memory object sorting
|
||||
@@ -763,5 +771,92 @@ ORDER BY contentNodeId, propertytypeid
|
||||
/// <param name="queryType"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract Sql GetBaseQuery(BaseQueryType queryType);
|
||||
|
||||
internal class DocumentDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
|
||||
/// </summary>
|
||||
public DocumentDefinition(int id, Guid version, DateTime versionDate, DateTime createDate, IContentTypeComposition composition)
|
||||
{
|
||||
Id = id;
|
||||
Version = version;
|
||||
VersionDate = versionDate;
|
||||
CreateDate = createDate;
|
||||
Composition = composition;
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public Guid Version { get; set; }
|
||||
public DateTime VersionDate { get; set; }
|
||||
public DateTime CreateDate { get; set; }
|
||||
public IContentTypeComposition Composition { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An object representing a query that may contain paging information
|
||||
/// </summary>
|
||||
internal class PagingSqlQuery
|
||||
{
|
||||
public Sql PrePagedSql { get; private set; }
|
||||
|
||||
public PagingSqlQuery(Sql prePagedSql)
|
||||
{
|
||||
PrePagedSql = prePagedSql;
|
||||
}
|
||||
|
||||
public virtual bool HasPaging
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public virtual Sql BuildPagedQuery(string selectColumns)
|
||||
{
|
||||
throw new InvalidOperationException("This query has no paging information");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An object representing a query that contains paging information
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class PagingSqlQuery<T> : PagingSqlQuery
|
||||
{
|
||||
private readonly Database _db;
|
||||
private readonly long _pageIndex;
|
||||
private readonly int _pageSize;
|
||||
|
||||
public PagingSqlQuery(Database db, Sql prePagedSql, long pageIndex, int pageSize) : base(prePagedSql)
|
||||
{
|
||||
_db = db;
|
||||
_pageIndex = pageIndex;
|
||||
_pageSize = pageSize;
|
||||
}
|
||||
|
||||
public override bool HasPaging
|
||||
{
|
||||
get { return _pageSize > 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a paged query based on the original query and subtitutes the selectColumns specified
|
||||
/// </summary>
|
||||
/// <param name="selectColumns"></param>
|
||||
/// <returns></returns>
|
||||
public override Sql BuildPagedQuery(string selectColumns)
|
||||
{
|
||||
if (HasPaging == false) throw new InvalidOperationException("This query has no paging information");
|
||||
|
||||
var resultSql = string.Format("SELECT {0} {1}", selectColumns, PrePagedSql.SQL.Substring(PrePagedSql.SQL.IndexOf("FROM", StringComparison.Ordinal)));
|
||||
|
||||
//this query is meant to be paged so we need to generate the paging syntax
|
||||
//Create the inner paged query that was used above to get the paged result, we'll use that as the inner sub query
|
||||
var args = PrePagedSql.Arguments;
|
||||
string sqlStringCount, sqlStringPage;
|
||||
_db.BuildPageQueries<T>(_pageIndex * _pageSize, _pageSize, resultSql, ref args, out sqlStringCount, out sqlStringPage);
|
||||
|
||||
return new Sql(sqlStringPage, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,23 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
internal static class SqlSyntaxProviderExtensions
|
||||
{
|
||||
public static IEnumerable<DbIndexDefinition> GetDefinedIndexesDefinitions(this ISqlSyntaxProvider sql, Database db)
|
||||
{
|
||||
return sql.GetDefinedIndexes(db)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the quotes tableName.columnName combo
|
||||
/// </summary>
|
||||
|
||||
@@ -735,6 +735,26 @@ namespace Umbraco.Core.Services
|
||||
return empty.Union(files.Except(empty));
|
||||
}
|
||||
|
||||
public void CreatePartialViewFolder(string folderPath)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreatePartialViewRepository(uow))
|
||||
{
|
||||
((PartialViewRepository)repository).AddFolder(folderPath);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void CreatePartialViewMacroFolder(string folderPath)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow))
|
||||
{
|
||||
((PartialViewMacroRepository)repository).AddFolder(folderPath);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void DeletePartialViewFolder(string folderPath)
|
||||
{
|
||||
using (var uow = _fileUowProvider.GetUnitOfWork())
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Umbraco.Core.Services
|
||||
public interface IFileService : IService
|
||||
{
|
||||
IEnumerable<string> GetPartialViewSnippetNames(params string[] filterNames);
|
||||
void CreatePartialViewFolder(string folderPath);
|
||||
void CreatePartialViewMacroFolder(string folderPath);
|
||||
void DeletePartialViewFolder(string folderPath);
|
||||
void DeletePartialViewMacroFolder(string folderPath);
|
||||
IPartialView GetPartialView(string path);
|
||||
|
||||
@@ -1716,6 +1716,24 @@ namespace Umbraco.Core.Services
|
||||
#region Package Building
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// This method can be used to trigger the 'ImportedPackage' event when a package is installed by something else but this service.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
internal static void OnImportedPackage(ImportPackageEventArgs<InstallationSummary> args)
|
||||
{
|
||||
ImportedPackage.RaiseEvent(args, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method can be used to trigger the 'UninstalledPackage' event when a package is uninstalled by something else but this service.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
internal static void OnUninstalledPackage(UninstallPackageEventArgs<UninstallationSummary> args)
|
||||
{
|
||||
UninstalledPackage.RaiseEvent(args, null);
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
/// <summary>
|
||||
/// Occurs before Importing Content
|
||||
@@ -1876,10 +1894,15 @@ namespace Umbraco.Core.Services
|
||||
internal static event TypedEventHandler<IPackagingService, ImportPackageEventArgs<string>> ImportingPackage;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after a apckage is imported
|
||||
/// Occurs after a package is imported
|
||||
/// </summary>
|
||||
internal static event TypedEventHandler<IPackagingService, ImportPackageEventArgs<InstallationSummary>> ImportedPackage;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after a package is uninstalled
|
||||
/// </summary>
|
||||
internal static event TypedEventHandler<IPackagingService, UninstallPackageEventArgs<UninstallationSummary>> UninstalledPackage;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(commit: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateRelationRepository(uow);
|
||||
var query = new Query<IRelation>().Where(x => x.ChildId == id || x.ParentId == id);
|
||||
var query = new Query<IRelation>().Where(x => x.ParentId == id || x.ChildId == id);
|
||||
return repository.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace Umbraco.Core.Services
|
||||
if (relationType == null) return Enumerable.Empty<IRelation>();
|
||||
|
||||
var relationRepo = RepositoryFactory.CreateRelationRepository(uow);
|
||||
var query = new Query<IRelation>().Where(x => (x.ChildId == id || x.ParentId == id) && x.RelationTypeId == relationType.Id);
|
||||
var query = new Query<IRelation>().Where(x => (x.ParentId == id || x.ChildId == id) && x.RelationTypeId == relationType.Id);
|
||||
return relationRepo.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,18 +285,30 @@ namespace Umbraco.Core
|
||||
var member = entity as IMember;
|
||||
if (member != null) return member.GetUdi();
|
||||
|
||||
var contentBase = entity as IContentBase;
|
||||
if (contentBase != null) return contentBase.GetUdi();
|
||||
var stylesheet = entity as Stylesheet;
|
||||
if (stylesheet != null) return stylesheet.GetUdi();
|
||||
|
||||
var script = entity as Script;
|
||||
if (script != null) return script.GetUdi();
|
||||
|
||||
var dictionaryItem = entity as IDictionaryItem;
|
||||
if (dictionaryItem != null) return dictionaryItem.GetUdi();
|
||||
|
||||
var macro = entity as IMacro;
|
||||
if (macro != null) return macro.GetUdi();
|
||||
|
||||
var partialView = entity as IPartialView;
|
||||
if (partialView != null) return partialView.GetUdi();
|
||||
|
||||
var xsltFile = entity as IXsltFile;
|
||||
if (xsltFile != null) return xsltFile.GetUdi();
|
||||
|
||||
var contentBase = entity as IContentBase;
|
||||
if (contentBase != null) return contentBase.GetUdi();
|
||||
|
||||
var relationType = entity as IRelationType;
|
||||
if (relationType != null) return relationType.GetUdi();
|
||||
|
||||
var dictionaryItem = entity as IDictionaryItem;
|
||||
if (dictionaryItem != null) return dictionaryItem.GetUdi();
|
||||
|
||||
throw new NotSupportedException(string.Format("Entity type {0} is not supported.", entity.GetType().FullName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +316,7 @@
|
||||
<Compile Include="Events\IDeletingMediaFilesEventArgs.cs" />
|
||||
<Compile Include="Events\ScopeEventDispatcherBase.cs" />
|
||||
<Compile Include="OrderedHashSet.cs" />
|
||||
<Compile Include="Events\UninstallPackageEventArgs.cs" />
|
||||
<Compile Include="Models\GridValue.cs" />
|
||||
<Compile Include="Deploy\IArtifact.cs" />
|
||||
<Compile Include="Deploy\IArtifactSignature.cs" />
|
||||
@@ -451,6 +452,7 @@
|
||||
<Compile Include="Models\DoNotCloneAttribute.cs" />
|
||||
<Compile Include="Models\IDomain.cs" />
|
||||
<Compile Include="NamedUdiRange.cs" />
|
||||
<Compile Include="Packaging\Models\UninstallationSummary.cs" />
|
||||
<Compile Include="Persistence\BulkDataReader.cs" />
|
||||
<Compile Include="Persistence\Constants-Locks.cs" />
|
||||
<Compile Include="Persistence\DatabaseNodeLockExtensions.cs" />
|
||||
@@ -480,6 +482,8 @@
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\AddUniqueIdPropertyTypeGroupColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\RemoveParentIdPropertyTypeGroupColumn.cs" />
|
||||
<Compile Include="Persistence\Mappers\TaskTypeMapper.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToCmsMemberLoginName.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexesToUmbracoRelationTables.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToUmbracoNodePath.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddRelationTypeUniqueIdColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddMacroUniqueIdColumn.cs" />
|
||||
|
||||
@@ -56,5 +56,14 @@ namespace Umbraco.Tests.IO
|
||||
Assert.AreEqual(IOHelper.MapPath(SystemDirectories.WebServices, true), IOHelper.MapPath(SystemDirectories.WebServices, false));
|
||||
Assert.AreEqual(IOHelper.MapPath(SystemDirectories.Xslt, true), IOHelper.MapPath(SystemDirectories.Xslt, false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnsurePathIsApplicationRootPrefixed()
|
||||
{
|
||||
//Assert
|
||||
Assert.AreEqual("~/Views/Template.cshtml", IOHelper.EnsurePathIsApplicationRootPrefixed("Views/Template.cshtml"));
|
||||
Assert.AreEqual("~/Views/Template.cshtml", IOHelper.EnsurePathIsApplicationRootPrefixed("/Views/Template.cshtml"));
|
||||
Assert.AreEqual("~/Views/Template.cshtml", IOHelper.EnsurePathIsApplicationRootPrefixed("~/Views/Template.cshtml"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,19 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine,
|
||||
Assert.AreEqual("CREATE UNIQUE NONCLUSTERED INDEX [IX_A] ON [TheTable] ([A])", createExpression.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateIndexBuilder_SqlServer_Unique_CreatesUniqueNonClusteredIndex_Multi_Columnn()
|
||||
{
|
||||
var sqlSyntax = new SqlServerSyntaxProvider();
|
||||
var createExpression = new CreateIndexExpression(DatabaseProviders.SqlServer, new[] { DatabaseProviders.SqlServer }, sqlSyntax)
|
||||
{
|
||||
Index = { Name = "IX_AB" }
|
||||
};
|
||||
var builder = new CreateIndexBuilder(createExpression);
|
||||
builder.OnTable("TheTable").OnColumn("A").Ascending().OnColumn("B").Ascending().WithOptions().Unique();
|
||||
Assert.AreEqual("CREATE UNIQUE NONCLUSTERED INDEX [IX_AB] ON [TheTable] ([A],[B])", createExpression.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateIndexBuilder_SqlServer_Clustered_CreatesClusteredIndex()
|
||||
{
|
||||
|
||||
@@ -40,27 +40,50 @@ Use this directive to generate a list of breadcrumbs.
|
||||
|
||||
@param {array} ancestors Array of ancestors
|
||||
@param {string} entityType The content entity type (member, media, content).
|
||||
@param {callback} Callback when an ancestor is clicked. It will override the default link behaviour.
|
||||
**/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function BreadcrumbsDirective() {
|
||||
function BreadcrumbsDirective() {
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/editor/umb-breadcrumbs.html',
|
||||
scope: {
|
||||
ancestors: "=",
|
||||
entityType: "@"
|
||||
}
|
||||
};
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
return directive;
|
||||
scope.allowOnOpen = false;
|
||||
|
||||
}
|
||||
scope.open = function(ancestor) {
|
||||
if(scope.onOpen && scope.allowOnOpen) {
|
||||
scope.onOpen({'ancestor': ancestor});
|
||||
}
|
||||
};
|
||||
|
||||
angular.module('umbraco.directives').directive('umbBreadcrumbs', BreadcrumbsDirective);
|
||||
function onInit() {
|
||||
if ("onOpen" in attr) {
|
||||
scope.allowOnOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
onInit();
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/editor/umb-breadcrumbs.html',
|
||||
scope: {
|
||||
ancestors: "=",
|
||||
entityType: "@",
|
||||
onOpen: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbBreadcrumbs', BreadcrumbsDirective);
|
||||
|
||||
})();
|
||||
|
||||
@@ -21,7 +21,8 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
customtreeparams: '@',
|
||||
eventhandler: '=',
|
||||
enablecheckboxes: '@',
|
||||
enablelistviewsearch: '@'
|
||||
enablelistviewsearch: '@',
|
||||
enablelistviewexpand: '@'
|
||||
},
|
||||
|
||||
compile: function(element, attrs) {
|
||||
@@ -35,7 +36,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
'<a class="umb-options" ng-hide="tree.root.isContainer || !tree.root.menuUrl" ng-click="options(tree.root, $event)" ng-swipe-right="options(tree.root, $event)"><i></i><i></i><i></i></a>' +
|
||||
'</div>';
|
||||
template += '<ul>' +
|
||||
'<umb-tree-item ng-repeat="child in tree.root.children" eventhandler="eventhandler" node="child" current-node="currentNode" tree="this" section="{{section}}" ng-animate="animation()"></umb-tree-item>' +
|
||||
'<umb-tree-item ng-repeat="child in tree.root.children" enablelistviewexpand="{{enablelistviewexpand}}" eventhandler="eventhandler" node="child" current-node="currentNode" tree="this" section="{{section}}" ng-animate="animation()"></umb-tree-item>' +
|
||||
'</ul>' +
|
||||
'</li>' +
|
||||
'</ul>';
|
||||
|
||||
@@ -27,6 +27,7 @@ angular.module("umbraco.directives")
|
||||
section: '@',
|
||||
eventhandler: '=',
|
||||
currentNode: '=',
|
||||
enablelistviewexpand: '@',
|
||||
node: '=',
|
||||
tree: '='
|
||||
},
|
||||
@@ -38,7 +39,7 @@ angular.module("umbraco.directives")
|
||||
'<div ng-class="getNodeCssClass(node)" ng-swipe-right="options(node, $event)" >' +
|
||||
//NOTE: This ins element is used to display the search icon if the node is a container/listview and the tree is currently in dialog
|
||||
//'<ins ng-if="tree.enablelistviewsearch && node.metaData.isContainer" class="umb-tree-node-search icon-search" ng-click="searchNode(node, $event)" alt="searchAltText"></ins>' +
|
||||
'<ins ng-class="{\'icon-navigation-right\': !node.expanded, \'icon-navigation-down\': node.expanded}" ng-click="load(node)"> </ins>' +
|
||||
'<ins ng-class="{\'icon-navigation-right\': !node.expanded || node.metaData.isContainer, \'icon-navigation-down\': node.expanded && !node.metaData.isContainer}" ng-click="load(node)"> </ins>' +
|
||||
'<i class="icon umb-tree-icon sprTree" ng-click="select(node, $event)"></i>' +
|
||||
'<a href="#/{{node.routePath}}" ng-click="select(node, $event)"></a>' +
|
||||
//NOTE: These are the 'option' elipses
|
||||
@@ -74,11 +75,12 @@ angular.module("umbraco.directives")
|
||||
|
||||
//toggle visibility of last 'ins' depending on children
|
||||
//visibility still ensure the space is "reserved", so both nodes with and without children are aligned.
|
||||
if (!node.hasChildren) {
|
||||
element.find("ins").last().css("visibility", "hidden");
|
||||
|
||||
if (node.hasChildren || node.metaData.isContainer && scope.enablelistviewexpand === "true") {
|
||||
element.find("ins").last().css("visibility", "visible");
|
||||
}
|
||||
else {
|
||||
element.find("ins").last().css("visibility", "visible");
|
||||
element.find("ins").last().css("visibility", "hidden");
|
||||
}
|
||||
|
||||
var icon = element.find("i:first");
|
||||
@@ -192,7 +194,7 @@ angular.module("umbraco.directives")
|
||||
emits treeNodeCollapsing event if already expanded and treeNodeExpanding if collapsed
|
||||
*/
|
||||
scope.load = function (node) {
|
||||
if (node.expanded) {
|
||||
if (node.expanded && !node.metaData.isContainer) {
|
||||
deleteAnimations = false;
|
||||
emitEvent("treeNodeCollapsing", { tree: scope.tree, node: node, element: element });
|
||||
node.expanded = false;
|
||||
@@ -227,7 +229,7 @@ angular.module("umbraco.directives")
|
||||
|
||||
setupNodeDom(scope.node, scope.tree);
|
||||
|
||||
var template = '<ul ng-class="{collapsed: !node.expanded}"><umb-tree-item ng-repeat="child in node.children" eventhandler="eventhandler" tree="tree" current-node="currentNode" node="child" section="{{section}}" ng-animate="animation()"></umb-tree-item></ul>';
|
||||
var template = '<ul ng-class="{collapsed: !node.expanded}"><umb-tree-item ng-repeat="child in node.children" enablelistviewexpand="{{enablelistviewexpand}}" eventhandler="eventhandler" tree="tree" current-node="currentNode" node="child" section="{{section}}" ng-animate="animation()"></umb-tree-item></ul>';
|
||||
var newElement = angular.element(template);
|
||||
$compile(newElement)(scope);
|
||||
element.append(newElement);
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function MiniListViewDirective(contentResource, memberResource, mediaResource) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
scope.search = "";
|
||||
scope.miniListViews = [];
|
||||
scope.breadcrumb = [];
|
||||
|
||||
var miniListViewsHistory = [];
|
||||
var goingForward = true;
|
||||
var skipAnimation = true;
|
||||
|
||||
function onInit() {
|
||||
open(scope.node);
|
||||
}
|
||||
|
||||
function open(node) {
|
||||
|
||||
goingForward = true;
|
||||
|
||||
var miniListView = {
|
||||
node: node,
|
||||
loading: true,
|
||||
pagination: {
|
||||
pageSize: 10,
|
||||
pageNumber: 1,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder",
|
||||
orderBySystemField: true
|
||||
}
|
||||
};
|
||||
|
||||
// clear and push mini list view in dom so we only render 1 view
|
||||
scope.miniListViews = [];
|
||||
scope.miniListViews.push(miniListView);
|
||||
|
||||
// store in history so we quickly can navigate back
|
||||
miniListViewsHistory.push(miniListView);
|
||||
|
||||
// get children
|
||||
getChildrenForMiniListView(miniListView);
|
||||
|
||||
makeBreadcrumb();
|
||||
|
||||
}
|
||||
|
||||
function getChildrenForMiniListView(miniListView) {
|
||||
|
||||
// start loading animation list view
|
||||
miniListView.loading = true;
|
||||
|
||||
// setup the correct resource depending on section
|
||||
var resource = "";
|
||||
|
||||
if (scope.entityType === "Member") {
|
||||
resource = memberResource.getPagedResults;
|
||||
} else if (scope.entityType === "Media") {
|
||||
resource = mediaResource.getChildren;
|
||||
} else {
|
||||
resource = contentResource.getChildren;
|
||||
}
|
||||
|
||||
resource(miniListView.node.id, miniListView.pagination)
|
||||
.then(function (data) {
|
||||
// update children
|
||||
miniListView.children = data.items;
|
||||
// update pagination
|
||||
miniListView.pagination.totalItems = data.totalItems;
|
||||
miniListView.pagination.totalPages = data.totalPages;
|
||||
// stop load indicator
|
||||
miniListView.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
scope.openNode = function(event, node) {
|
||||
open(node);
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
scope.selectNode = function(node) {
|
||||
if(scope.onSelect) {
|
||||
scope.onSelect({'node': node});
|
||||
}
|
||||
};
|
||||
|
||||
/* Pagination */
|
||||
scope.goToPage = function(pageNumber, miniListView) {
|
||||
// set new page number
|
||||
miniListView.pagination.pageNumber = pageNumber;
|
||||
// get children
|
||||
getChildrenForMiniListView(miniListView);
|
||||
};
|
||||
|
||||
/* Breadcrumb */
|
||||
scope.clickBreadcrumb = function(ancestor) {
|
||||
|
||||
var found = false;
|
||||
goingForward = false;
|
||||
|
||||
angular.forEach(miniListViewsHistory, function(historyItem, index){
|
||||
// We need to make sure we can compare the two id's.
|
||||
// Some id's are integers and others are strings.
|
||||
// Members have string ids like "all-members".
|
||||
if(historyItem.node.id.toString() === ancestor.id.toString()) {
|
||||
// load the list view from history
|
||||
scope.miniListViews = [];
|
||||
scope.miniListViews.push(historyItem);
|
||||
// clean up history - remove all children after
|
||||
miniListViewsHistory.splice(index + 1, miniListViewsHistory.length);
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(!found) {
|
||||
// if we can't find the view in the history - close the list view
|
||||
scope.exitMiniListView();
|
||||
}
|
||||
|
||||
// update the breadcrumb
|
||||
makeBreadcrumb();
|
||||
|
||||
};
|
||||
|
||||
scope.showBackButton = function() {
|
||||
// don't show the back button if the start node is a list view
|
||||
if(scope.node.metaData && scope.node.metaData.IsContainer || scope.node.isContainer) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
scope.exitMiniListView = function() {
|
||||
miniListViewsHistory = [];
|
||||
scope.miniListViews = [];
|
||||
if(scope.onClose) {
|
||||
scope.onClose();
|
||||
}
|
||||
};
|
||||
|
||||
function makeBreadcrumb() {
|
||||
scope.breadcrumb = [];
|
||||
angular.forEach(miniListViewsHistory, function(historyItem){
|
||||
scope.breadcrumb.push(historyItem.node);
|
||||
});
|
||||
}
|
||||
|
||||
/* Search */
|
||||
scope.searchMiniListView = function(search, miniListView) {
|
||||
// set search value
|
||||
miniListView.pagination.filter = search;
|
||||
// reset pagination
|
||||
miniListView.pagination.pageNumber = 1;
|
||||
// start loading animation list view
|
||||
miniListView.loading = true;
|
||||
searchMiniListView(miniListView);
|
||||
};
|
||||
|
||||
var searchMiniListView = _.debounce(function (miniListView) {
|
||||
scope.$apply(function () {
|
||||
getChildrenForMiniListView(miniListView);
|
||||
});
|
||||
}, 500);
|
||||
|
||||
/* Animation */
|
||||
scope.getMiniListViewAnimation = function() {
|
||||
|
||||
// disable the first "slide-in-animation"" if the start node is a list view
|
||||
if(scope.node.metaData && scope.node.metaData.IsContainer && skipAnimation || scope.node.isContainer && skipAnimation) {
|
||||
skipAnimation = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(goingForward) {
|
||||
return 'umb-mini-list-view--forward';
|
||||
} else {
|
||||
return 'umb-mini-list-view--backwards';
|
||||
}
|
||||
};
|
||||
|
||||
onInit();
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/umb-mini-list-view.html',
|
||||
scope: {
|
||||
node: "=",
|
||||
entityType: "@",
|
||||
startNodeId: "=",
|
||||
onSelect: "&",
|
||||
onClose: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbMiniListView', MiniListViewDirective);
|
||||
|
||||
})();
|
||||
@@ -134,25 +134,40 @@ Use this directive to generate a pagination.
|
||||
|
||||
}
|
||||
|
||||
scope.next = function() {
|
||||
if (scope.onNext && scope.pageNumber < scope.totalPages) {
|
||||
scope.pageNumber++;
|
||||
scope.onNext(scope.pageNumber);
|
||||
}
|
||||
scope.next = function () {
|
||||
if (scope.pageNumber < scope.totalPages) {
|
||||
scope.pageNumber++;
|
||||
if (scope.onNext) {
|
||||
scope.onNext(scope.pageNumber);
|
||||
}
|
||||
if (scope.onChange) {
|
||||
scope.onChange({ "pageNumber": scope.pageNumber });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.prev = function(pageNumber) {
|
||||
if (scope.onPrev && scope.pageNumber > 1) {
|
||||
scope.pageNumber--;
|
||||
scope.onPrev(scope.pageNumber);
|
||||
}
|
||||
scope.prev = function (pageNumber) {
|
||||
if (scope.pageNumber > 1) {
|
||||
scope.pageNumber--;
|
||||
if (scope.onPrev) {
|
||||
scope.onPrev(scope.pageNumber);
|
||||
}
|
||||
if (scope.onChange) {
|
||||
scope.onChange({ "pageNumber": scope.pageNumber });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.goToPage = function(pageNumber) {
|
||||
if(scope.onGoToPage) {
|
||||
scope.pageNumber = pageNumber + 1;
|
||||
scope.onGoToPage(scope.pageNumber);
|
||||
}
|
||||
scope.goToPage = function (pageNumber) {
|
||||
scope.pageNumber = pageNumber + 1;
|
||||
if (scope.onGoToPage) {
|
||||
scope.onGoToPage(scope.pageNumber);
|
||||
}
|
||||
if (scope.onChange) {
|
||||
if (scope.onChange) {
|
||||
scope.onChange({ "pageNumber": scope.pageNumber });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var unbindPageNumberWatcher = scope.$watch('pageNumber', function(newValue, oldValue){
|
||||
@@ -176,7 +191,8 @@ Use this directive to generate a pagination.
|
||||
totalPages: "=",
|
||||
onNext: "=",
|
||||
onPrev: "=",
|
||||
onGoToPage: "="
|
||||
onGoToPage: "=",
|
||||
onChange: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
@@ -205,6 +205,38 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
"codeFileApiBaseUrl",
|
||||
"GetScaffold?type=" + type + "&id=" + id + "&snippetName=" + snippetName)),
|
||||
"Failed to get scaffold for" + type);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.codefileResource#createContainer
|
||||
* @methodOf umbraco.resources.codefileResource
|
||||
*
|
||||
* @description
|
||||
* Creates a container/folder
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* codefileResource.createContainer("partialViews", "folder%2ffolder", "folder")
|
||||
* .then(function(data) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {string} File type: (scripts, partialViews, partialViewMacros).
|
||||
* @param {string} Parent Id: url encoded path
|
||||
* @param {string} Container name
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
|
||||
createContainer: function(type, parentId, name) {
|
||||
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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -118,6 +118,8 @@
|
||||
@import "components/umb-avatar.less";
|
||||
@import "components/umb-progress-bar.less";
|
||||
@import "components/umb-querybuilder.less";
|
||||
@import "components/umb-pagination.less";
|
||||
@import "components/umb-mini-list-view.less";
|
||||
|
||||
@import "components/buttons/umb-button.less";
|
||||
@import "components/buttons/umb-button-group.less";
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
.umb-mini-list-view__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__title-text {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__title-icon {
|
||||
font-size: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__back {
|
||||
font-size: 11px;
|
||||
margin-right: 5px;
|
||||
color: @gray;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__back-icon {
|
||||
margin-right: 4px;
|
||||
height: 11px;
|
||||
line-height: 11px;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__back-text {
|
||||
text-decoration: underline;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__back:hover {
|
||||
opacity: 1;
|
||||
text-decoration: none;
|
||||
color: @black;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
|
||||
/* Forward */
|
||||
|
||||
.umb-mini-list-view--forward-enter,
|
||||
.umb-mini-list-view--forward-leave
|
||||
{
|
||||
transition: 120ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--forward-enter {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--forward-enter.umb-mini-list-view--forward-enter-active {
|
||||
left: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--forward-leave {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--forward-leave.umb-mini-list-view--forward-leave-active{
|
||||
left: -100%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Backwards */
|
||||
|
||||
.umb-mini-list-view--backwards-enter,
|
||||
.umb-mini-list-view--backwards-leave
|
||||
{
|
||||
transition: 120ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--backwards-enter {
|
||||
right: 100%;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--backwards-enter.umb-mini-list-view--backwards-enter-active {
|
||||
right: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--backwards-leave {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--backwards-leave.umb-mini-list-view--backwards-leave-active{
|
||||
right: -100%;
|
||||
opacity: 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.umb-pagination ul {
|
||||
box-shadow: none;
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
|
||||
min-width: 640px;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.umb-table.umb-table-inactive {
|
||||
@@ -103,11 +103,17 @@ input.umb-table__input {
|
||||
|
||||
|
||||
// Table Body Styles
|
||||
.umb-table-body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-table-body .umb-table-row {
|
||||
color: fade(@gray, 75%);
|
||||
border-top: 1px solid @grayLight;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
position: relative;
|
||||
min-height: 32px;
|
||||
|
||||
&:hover {
|
||||
background-color: fade(@grayLighter, 90%);
|
||||
@@ -198,30 +204,33 @@ input.umb-table__input {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Table Row Styles
|
||||
.umb-table-row {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.umb-table-body .umb-table-row--empty {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 5px 0;
|
||||
cursor: auto;
|
||||
user-select: auto;
|
||||
}
|
||||
|
||||
.umb-table-body .umb-table-row--empty:hover {
|
||||
background-color: transparent;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.umb-table-row.-selected,
|
||||
.umb-table-row.-selected:hover {
|
||||
background-color: fade(@blueDark, 4%);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Table Cell Styles
|
||||
.umb-table-cell {
|
||||
display: flex;
|
||||
@@ -250,9 +259,44 @@ input.umb-table__input {
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
.umb-table-cell--auto-width {
|
||||
flex: 0 0 auto !important;
|
||||
}
|
||||
|
||||
.umb-table-cell--faded {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
|
||||
// Increases the space for the name cell
|
||||
.umb-table__name {
|
||||
flex: 1 1 25%;
|
||||
max-width: 25%;
|
||||
}
|
||||
|
||||
.umb-table__loading-overlay {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.umb-table__row-expand {
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
color: @black;
|
||||
}
|
||||
|
||||
.umb-table--condensed {
|
||||
|
||||
.umb-table-cell:first-of-type:not(.not-fixed) {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.umb-table-body__icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
.red{color: @red;}
|
||||
.blue{color: @blue;}
|
||||
.black{color: @black;}
|
||||
|
||||
|
||||
//icon colors for tree icons
|
||||
@@ -351,4 +352,4 @@
|
||||
// SORTABLE
|
||||
// --------------------------------------------------
|
||||
@sortableHelperBg: rgba(4, 156, 219, 0.5);
|
||||
@sortablePlaceholderBg : @blue;
|
||||
@sortablePlaceholderBg : @blue;
|
||||
|
||||
@@ -1,34 +1,48 @@
|
||||
<div ng-controller="Umbraco.Overlays.TreePickerController" ng-init="init('content')">
|
||||
|
||||
<div class="umb-control-group">
|
||||
<umb-tree-search-box
|
||||
hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
search-from-id="{{searchInfo.searchFromId}}"
|
||||
search-from-name="{{searchInfo.searchFromName}}"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="content">
|
||||
</umb-tree-search-box>
|
||||
</div>
|
||||
<div ng-hide="miniListView">
|
||||
|
||||
<umb-tree-search-results
|
||||
ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
<div class="umb-control-group">
|
||||
<umb-tree-search-box
|
||||
hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
search-from-id="{{searchInfo.searchFromId}}"
|
||||
search-from-name="{{searchInfo.searchFromName}}"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="content">
|
||||
</umb-tree-search-box>
|
||||
</div>
|
||||
|
||||
<div ng-hide="searchInfo.showSearch" ng-animate="'tree-fade-out'">
|
||||
<umb-tree
|
||||
section="content"
|
||||
treealias="content"
|
||||
hideheader="{{hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
customtreeparams="{{customTreeParams}}"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablelistviewsearch="true"
|
||||
enablecheckboxes="{{multiPicker}}">
|
||||
</umb-tree>
|
||||
</div>
|
||||
<umb-tree-search-results
|
||||
ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
|
||||
</div>
|
||||
<div ng-hide="searchInfo.showSearch" ng-animate="'tree-fade-out'">
|
||||
<umb-tree
|
||||
section="content"
|
||||
treealias="content"
|
||||
hideheader="{{hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
customtreeparams="{{customTreeParams}}"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablelistviewsearch="true"
|
||||
enablelistviewexpand="true"
|
||||
enablecheckboxes="{{multiPicker}}">
|
||||
</umb-tree>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<umb-mini-list-view
|
||||
ng-if="miniListView"
|
||||
node="miniListView"
|
||||
entity-type="{{entityType}}"
|
||||
start-node-id="model.startNodeId"
|
||||
on-select="selectListViewNode(node)"
|
||||
on-close="closeMiniListView()">
|
||||
</umb-mini-list-view>
|
||||
|
||||
</div>
|
||||
@@ -1,34 +1,47 @@
|
||||
<div ng-controller="Umbraco.Overlays.TreePickerController" ng-init="init('member')">
|
||||
|
||||
<div class="umb-control-group">
|
||||
<umb-tree-search-box
|
||||
hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
search-from-id="{{searchInfo.searchFromId}}"
|
||||
search-from-name="{{searchInfo.searchFromName}}"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="member">
|
||||
</umb-tree-search-box>
|
||||
</div>
|
||||
<div ng-hide="miniListView">
|
||||
|
||||
<umb-tree-search-results
|
||||
ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
<div class="umb-control-group">
|
||||
<umb-tree-search-box
|
||||
hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
search-from-id="{{searchInfo.searchFromId}}"
|
||||
search-from-name="{{searchInfo.searchFromName}}"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="member">
|
||||
</umb-tree-search-box>
|
||||
</div>
|
||||
|
||||
<div ng-hide="searchInfo.showSearch" ng-animate="'tree-fade-out'">
|
||||
<umb-tree
|
||||
section="member"
|
||||
treealias="member"
|
||||
hideheader="{{hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
customtreeparams="{{customTreeParams}}"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablelistviewsearch="true"
|
||||
enablecheckboxes="{{multiPicker}}">
|
||||
</umb-tree>
|
||||
</div>
|
||||
<umb-tree-search-results
|
||||
ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
|
||||
<div ng-hide="searchInfo.showSearch" ng-animate="'tree-fade-out'">
|
||||
<umb-tree
|
||||
section="member"
|
||||
treealias="member"
|
||||
hideheader="{{hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
customtreeparams="{{customTreeParams}}"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablelistviewsearch="true"
|
||||
enablelistviewexpand="true"
|
||||
enablecheckboxes="{{multiPicker}}">
|
||||
</umb-tree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<umb-mini-list-view
|
||||
ng-if="miniListView"
|
||||
node="miniListView"
|
||||
entity-type="{{entityType}}"
|
||||
start-node-id="model.startNodeId"
|
||||
on-select="selectListViewNode(node)"
|
||||
on-close="closeMiniListView()">
|
||||
</umb-mini-list-view>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
function ($scope, entityResource, eventsService, $log, searchService, angularHelper, $timeout, localizationService, treeService) {
|
||||
function ($scope, $q, entityResource, eventsService, $log, searchService, angularHelper, $timeout, localizationService, treeService, contentResource, mediaResource, memberResource) {
|
||||
|
||||
var tree = null;
|
||||
var dialogOptions = $scope.model;
|
||||
@@ -22,27 +22,22 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
$scope.init = function(contentType) {
|
||||
|
||||
if(contentType === "content") {
|
||||
entityType = "Document";
|
||||
$scope.entityType = "Document";
|
||||
if(!$scope.model.title) {
|
||||
$scope.model.title = localizationService.localize("defaultdialogs_selectContent");
|
||||
}
|
||||
} else if(contentType === "member") {
|
||||
entityType = "Member";
|
||||
$scope.entityType = "Member";
|
||||
if(!$scope.model.title) {
|
||||
$scope.model.title = localizationService.localize("defaultdialogs_selectMember");
|
||||
}
|
||||
} else if(contentType === "media") {
|
||||
entityType = "Media";
|
||||
$scope.entityType = "Media";
|
||||
if(!$scope.model.title) {
|
||||
$scope.model.title = localizationService.localize("defaultdialogs_selectMedia");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search is only working for content, media and member section so we will remove it from everything else
|
||||
if($scope.section === "content" || $scope.section === "media" || $scope.section === "member" ) {
|
||||
$scope.enableSearh = true;
|
||||
}
|
||||
|
||||
//create the custom query string param for this tree
|
||||
$scope.customTreeParams = dialogOptions.startNodeId ? "startNodeId=" + dialogOptions.startNodeId : "";
|
||||
@@ -54,7 +49,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
});
|
||||
|
||||
// Allow the entity type to be passed in but defaults to Document for backwards compatibility.
|
||||
var entityType = dialogOptions.entityType ? dialogOptions.entityType : "Document";
|
||||
$scope.entityType = dialogOptions.entityType ? dialogOptions.entityType : "Document";
|
||||
|
||||
|
||||
//min / max values
|
||||
@@ -66,10 +61,24 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
}
|
||||
|
||||
if (dialogOptions.section === "member") {
|
||||
entityType = "Member";
|
||||
$scope.entityType = "Member";
|
||||
}
|
||||
else if (dialogOptions.section === "media") {
|
||||
entityType = "Media";
|
||||
$scope.entityType = "Media";
|
||||
}
|
||||
|
||||
// Search and listviews is only working for content, media and member section so we will remove it from everything else
|
||||
if ($scope.section === "content" || $scope.section === "media" || $scope.section === "member") {
|
||||
$scope.enableSearh = true;
|
||||
|
||||
//if a alternative startnode is used, we need to check if it is a container
|
||||
if (dialogOptions.startNodeId && dialogOptions.startNodeId !== -1) {
|
||||
entityResource.getById(dialogOptions.startNodeId, $scope.entityType).then(function (node) {
|
||||
if (node.metaData.IsContainer) {
|
||||
openMiniListView(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//Configures filtering
|
||||
@@ -101,54 +110,17 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
}
|
||||
|
||||
function nodeExpandedHandler(ev, args) {
|
||||
|
||||
// open mini list view for list views
|
||||
if (args.node.metaData.isContainer) {
|
||||
openMiniListView(args.node);
|
||||
}
|
||||
|
||||
if (angular.isArray(args.children)) {
|
||||
|
||||
//iterate children
|
||||
_.each(args.children, function (child) {
|
||||
|
||||
//check if any of the items are list views, if so we need to add some custom
|
||||
// children: A node to activate the search, any nodes that have already been
|
||||
// selected in the search
|
||||
if (child.metaData.isContainer) {
|
||||
child.hasChildren = true;
|
||||
child.children = [
|
||||
{
|
||||
level: child.level + 1,
|
||||
hasChildren: false,
|
||||
parent: function () {
|
||||
return child;
|
||||
},
|
||||
name: searchText,
|
||||
metaData: {
|
||||
listViewNode: child,
|
||||
},
|
||||
cssClass: "icon-search",
|
||||
cssClasses: ["not-published"]
|
||||
}
|
||||
];
|
||||
//add base transition classes to this node
|
||||
child.cssClasses.push("tree-node-slide-up");
|
||||
|
||||
var listViewResults = _.filter($scope.searchInfo.selectedSearchResults, function(i) {
|
||||
return i.parentId == child.id;
|
||||
});
|
||||
_.each(listViewResults, function(item) {
|
||||
child.children.unshift({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
cssClass: "icon umb-tree-icon sprTree " + item.icon,
|
||||
level: child.level + 1,
|
||||
metaData: {
|
||||
isSearchResult: true
|
||||
},
|
||||
hasChildren: false,
|
||||
parent: function () {
|
||||
return child;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//now we need to look in the already selected search results and
|
||||
// toggle the check boxes for those ones that are listed
|
||||
var exists = _.find($scope.searchInfo.selectedSearchResults, function (selected) {
|
||||
@@ -174,18 +146,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
|
||||
if (args.node.metaData.listViewNode) {
|
||||
//check if list view 'search' node was selected
|
||||
|
||||
$scope.searchInfo.showSearch = true;
|
||||
$scope.searchInfo.searchFromId = args.node.metaData.listViewNode.id;
|
||||
$scope.searchInfo.searchFromName = args.node.metaData.listViewNode.name;
|
||||
|
||||
//add transition classes
|
||||
var listViewNode = args.node.parent();
|
||||
listViewNode.cssClasses.push('tree-node-slide-up-hide-active');
|
||||
}
|
||||
else if (args.node.metaData.isSearchResult) {
|
||||
if (args.node.metaData.isSearchResult) {
|
||||
//check if the item selected was a search result from a list view
|
||||
|
||||
//unselect
|
||||
@@ -232,7 +193,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
multiSelectItem(entity);
|
||||
} else {
|
||||
//otherwise we have to get it from the server
|
||||
entityResource.getById(id, entityType).then(function (ent) {
|
||||
entityResource.getById(id, $scope.entityType).then(function (ent) {
|
||||
multiSelectItem(ent);
|
||||
});
|
||||
}
|
||||
@@ -257,7 +218,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
multiSelectItem(entity);
|
||||
} else {
|
||||
//otherwise we have to get it from the server
|
||||
entityResource.getById(id, entityType).then(function (ent) {
|
||||
entityResource.getById(id, $scope.entityType).then(function (ent) {
|
||||
multiSelectItem(ent);
|
||||
});
|
||||
}
|
||||
@@ -274,7 +235,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
$scope.model.submit($scope.model);
|
||||
} else {
|
||||
//otherwise we have to get it from the server
|
||||
entityResource.getById(id, entityType).then(function (ent) {
|
||||
entityResource.getById(id, $scope.entityType).then(function (ent) {
|
||||
$scope.model.selection.push(ent);
|
||||
$scope.model.submit($scope.model);
|
||||
});
|
||||
@@ -355,7 +316,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
}
|
||||
|
||||
$scope.multiSubmit = function (result) {
|
||||
entityResource.getByIds(result, entityType).then(function (ents) {
|
||||
entityResource.getByIds(result, $scope.entityType).then(function (ents) {
|
||||
$scope.submit(ents);
|
||||
});
|
||||
};
|
||||
@@ -504,4 +465,19 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
|
||||
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
|
||||
});
|
||||
|
||||
$scope.selectListViewNode = function(node) {
|
||||
select(node.name, node.id);
|
||||
//toggle checked state
|
||||
node.selected = node.selected === true ? false : true;
|
||||
};
|
||||
|
||||
$scope.closeMiniListView = function() {
|
||||
$scope.miniListView = undefined;
|
||||
};
|
||||
|
||||
function openMiniListView(node) {
|
||||
$scope.miniListView = node;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -1,35 +1,49 @@
|
||||
<div ng-controller="Umbraco.Overlays.TreePickerController">
|
||||
|
||||
<div class="umb-control-group">
|
||||
<umb-tree-search-box
|
||||
ng-if="enableSearh"
|
||||
hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
search-from-id="{{searchInfo.searchFromId}}"
|
||||
search-from-name="{{searchInfo.searchFromName}}"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="{{section}}">
|
||||
</umb-tree-search-box>
|
||||
</div>
|
||||
<div ng-hide="miniListView">
|
||||
|
||||
<umb-tree-search-results
|
||||
ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
<div class="umb-control-group">
|
||||
<umb-tree-search-box
|
||||
ng-if="enableSearh"
|
||||
hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
search-from-id="{{searchInfo.searchFromId}}"
|
||||
search-from-name="{{searchInfo.searchFromName}}"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="{{section}}">
|
||||
</umb-tree-search-box>
|
||||
</div>
|
||||
|
||||
<div ng-hide="searchInfo.showSearch" ng-animate="'tree-fade-out'">
|
||||
<umb-tree
|
||||
section="{{section}}"
|
||||
treealias="{{treeAlias}}"
|
||||
hideheader="{{hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
customtreeparams="{{customTreeParams}}"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablelistviewsearch="true"
|
||||
enablecheckboxes="{{multiPicker}}">
|
||||
</umb-tree>
|
||||
</div>
|
||||
<umb-tree-search-results
|
||||
ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
|
||||
</div>
|
||||
<div ng-hide="searchInfo.showSearch" ng-animate="'tree-fade-out'">
|
||||
<umb-tree
|
||||
section="{{section}}"
|
||||
treealias="{{treeAlias}}"
|
||||
hideheader="{{hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
customtreeparams="{{customTreeParams}}"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
enablelistviewsearch="true"
|
||||
enablelistviewexpand="true"
|
||||
enablecheckboxes="{{multiPicker}}">
|
||||
</umb-tree>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<umb-mini-list-view
|
||||
ng-if="miniListView"
|
||||
node="miniListView"
|
||||
entity-type="{{entityType}}"
|
||||
start-node-id="model.startNodeId"
|
||||
on-select="selectListViewNode(node)"
|
||||
on-close="closeMiniListView()">
|
||||
</umb-mini-list-view>
|
||||
|
||||
</div>
|
||||
@@ -1,10 +1,15 @@
|
||||
<ul class="umb-breadcrumbs">
|
||||
<li class="umb-breadcrumbs__ancestor" ng-repeat="ancestor in ancestors">
|
||||
<li class="umb-breadcrumbs__ancestor" ng-repeat="ancestor in ancestors">
|
||||
|
||||
<!-- go to node on click -->
|
||||
<a ng-if="!$last && !allowOnOpen" href="#/{{entityType}}/{{entityType}}/edit/{{ancestor.id}}" class="umb-breadcrumbs__ancestor-link" title="{{ancestor.name}}">{{ancestor.name}}</a>
|
||||
|
||||
<a ng-if="!$last" href="#/{{entityType}}/{{entityType}}/edit/{{ancestor.id}}" class="umb-breadcrumbs__ancestor-link" title="{{ancestor.name}}">{{ancestor.name}}</a>
|
||||
<span ng-if="!$last" class="umb-breadcrumbs__seperator">/</span>
|
||||
<!-- use callback to handle click -->
|
||||
<a ng-if="!$last && allowOnOpen" href="#" ng-click="open(ancestor)" class="umb-breadcrumbs__ancestor-link" title="{{ancestor.name}}" prevent-default>{{ancestor.name}}</a>
|
||||
|
||||
<span class="umb-breadcrumbs__ancestor-text" ng-if="$last" title="{{ancestor.name}}">{{ancestor.name}}</span>
|
||||
<span ng-if="!$last" class="umb-breadcrumbs__seperator">/</span>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<span class="umb-breadcrumbs__ancestor-text" ng-if="$last" title="{{ancestor.name}}">{{ancestor.name}}</span>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,101 @@
|
||||
<div>
|
||||
|
||||
<div ng-repeat="miniListView in miniListViews" ng-animate="getMiniListViewAnimation()">
|
||||
|
||||
<div class="umb-mini-list-view__title">
|
||||
<i class="umb-mini-list-view__title-icon {{ miniListView.node.icon }}"></i>
|
||||
<h4 class="umb-mini-list-view__title-text">{{ miniListView.node.name }}</h4>
|
||||
</div>
|
||||
|
||||
<div class="flex" style="margin-bottom: 10px;">
|
||||
|
||||
<a ng-if="showBackButton()" href="" class="umb-mini-list-view__back" ng-click="exitMiniListView()">
|
||||
<i class="icon-arrow-left umb-mini-list-view__back-icon"></i>
|
||||
<span class="umb-mini-list-view__back-text">Back</span> /
|
||||
</a>
|
||||
|
||||
<umb-breadcrumbs
|
||||
ng-if="breadcrumb && breadcrumb.length > 0"
|
||||
ancestors="breadcrumb"
|
||||
entity-type="content"
|
||||
on-open="clickBreadcrumb(ancestor)">
|
||||
</umb-breadcrumbs>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="umb-table umb-table--condensed">
|
||||
|
||||
<!-- Head -->
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell" style="display: none;"></div>
|
||||
<div class="umb-table-cell" style="padding-top: 8px; padding-bottom: 8px;">
|
||||
<form class="form-search -no-margin-bottom" style="width: 100%; margin-right: 0;" novalidate>
|
||||
<div class="inner-addon left-addon">
|
||||
<i class="icon icon-search" style="font-size: 14px;"></i>
|
||||
<input
|
||||
style="width: 100%;"
|
||||
class="form-control search-input"
|
||||
type="text"
|
||||
localize="placeholder"
|
||||
placeholder="@general_typeToSearch"
|
||||
ng-model="search"
|
||||
ng-change="searchMiniListView(search, miniListView)"
|
||||
prevent-enter-submit
|
||||
no-dirty-check>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="umb-table-body">
|
||||
|
||||
<!-- Load indicator when the list has items -->
|
||||
<div class="umb-table__loading-overlay" ng-if="miniListView.loading && miniListView.children.length > 0">
|
||||
<umb-load-indicator></umb-load-indicator>
|
||||
</div>
|
||||
|
||||
<!-- Items -->
|
||||
<div class="umb-table-row"
|
||||
ng-repeat="child in miniListView.children"
|
||||
ng-click="selectNode(child)"
|
||||
ng-class="{'-selected':child.selected}">
|
||||
<div class="umb-table-cell umb-table-cell--auto-width" ng-class="{'umb-table-cell--faded':!child.published && entityType === 'Document'}">
|
||||
<div class="flex items-center">
|
||||
<ins class="icon-navigation-right umb-table__row-expand" ng-click="openNode($event, child)"> </ins>
|
||||
<i class="umb-table-body__icon umb-table-body__fileicon {{child.icon}}"></i>
|
||||
<i class="umb-table-body__icon umb-table-body__checkicon icon-check"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-cell black" ng-class="{'umb-table-cell--faded':!child.published && entityType === 'Document'}">{{ child.name }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Load indicator when the list doesn't have items -->
|
||||
<div ng-if="!miniListView.loading && !miniListView.children" class="umb-table-row umb-table-row--empty">
|
||||
<span ng-if="search === ''"><localize key="general_noItemsInList"></localize></span>
|
||||
<span ng-if="search !== ''"><localize key="general_searchNoResult"></localize></span>
|
||||
</div>
|
||||
|
||||
<!-- Load indicator when the list doesn't have items -->
|
||||
<div ng-if="miniListView.loading && !miniListView.children" class="umb-table-row umb-table-row--empty">
|
||||
<umb-load-indicator></umb-load-indicator>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<umb-pagination
|
||||
ng-if="miniListView.pagination.totalPages > 0 && !miniListView.loading"
|
||||
page-number="miniListView.pagination.pageNumber"
|
||||
total-pages="miniListView.pagination.totalPages"
|
||||
on-change="goToPage(pageNumber, miniListView)">
|
||||
</umb-pagination>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="pagination" ng-show="pagination.length > 1">
|
||||
<div class="umb-pagination pagination" ng-show="pagination.length > 1">
|
||||
|
||||
<ul>
|
||||
<li ng-class="{disabled:pageNumber <= 1}">
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function PartialViewMacrosCreateController($scope, codefileResource, $location, navigationService) {
|
||||
function PartialViewMacrosCreateController($scope, codefileResource, $location, navigationService, formHelper, localizationService, appState) {
|
||||
|
||||
var vm = this;
|
||||
var node = $scope.dialogOptions.currentNode;
|
||||
var localizeCreateFolder = localizationService.localize("defaultdialog_createFolder");
|
||||
|
||||
vm.snippets = [];
|
||||
vm.showSnippets = false;
|
||||
vm.creatingFolder = false;
|
||||
vm.createFolderError = "";
|
||||
vm.folderName = "";
|
||||
|
||||
vm.createPartialViewMacro = createPartialViewMacro;
|
||||
vm.showCreateFolder = showCreateFolder;
|
||||
@@ -39,8 +42,38 @@
|
||||
vm.creatingFolder = true;
|
||||
}
|
||||
|
||||
function createFolder() {
|
||||
function createFolder(form) {
|
||||
if (formHelper.submitForm({scope: $scope, formCtrl: form, statusMessage: localizeCreateFolder})) {
|
||||
|
||||
codefileResource.createContainer("partialViewMacros", node.id, vm.folderName).then(function (saved) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
|
||||
navigationService.syncTree({
|
||||
tree: "partialViewMacros",
|
||||
path: saved.path,
|
||||
forceReload: true,
|
||||
activate: true
|
||||
});
|
||||
|
||||
formHelper.resetForm({
|
||||
scope: $scope
|
||||
});
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
|
||||
}, function(err) {
|
||||
|
||||
vm.createFolderError = err;
|
||||
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showCreateFromSnippet() {
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
<!-- Create folder -->
|
||||
<div class="umb-pane" ng-if="vm.creatingFolder">
|
||||
<form novalidate name="createFolderForm"
|
||||
ng-submit="vm.createFolder()"
|
||||
val-form-manager>
|
||||
ng-submit="vm.createFolder(createFolderForm)"
|
||||
val-form-manager>
|
||||
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
<div ng-show="vm.createFolderError">
|
||||
<h5 class="text-error">{{vm.createFolderError.errorMsg}}</h5>
|
||||
<p class="text-error">{{vm.createFolderError.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function PartialViewsCreateController($scope, codefileResource, $location, navigationService) {
|
||||
function PartialViewsCreateController($scope, codefileResource, $location, navigationService, formHelper, localizationService, appState) {
|
||||
|
||||
var vm = this;
|
||||
var node = $scope.dialogOptions.currentNode;
|
||||
var localizeCreateFolder = localizationService.localize("defaultdialog_createFolder");
|
||||
|
||||
vm.snippets = [];
|
||||
vm.showSnippets = false;
|
||||
vm.creatingFolder = false;
|
||||
vm.createFolderError = "";
|
||||
vm.folderName = "";
|
||||
|
||||
vm.createPartialView = createPartialView;
|
||||
vm.showCreateFolder = showCreateFolder;
|
||||
@@ -39,8 +42,38 @@
|
||||
vm.creatingFolder = true;
|
||||
}
|
||||
|
||||
function createFolder() {
|
||||
function createFolder(form) {
|
||||
if (formHelper.submitForm({scope: $scope, formCtrl: form, statusMessage: localizeCreateFolder})) {
|
||||
|
||||
codefileResource.createContainer("partialViews", node.id, vm.folderName).then(function(saved) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
|
||||
navigationService.syncTree({
|
||||
tree: "partialViews",
|
||||
path: saved.path,
|
||||
forceReload: true,
|
||||
activate: true
|
||||
});
|
||||
|
||||
formHelper.resetForm({
|
||||
scope: $scope
|
||||
});
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
|
||||
}, function(err) {
|
||||
|
||||
vm.createFolderError = err;
|
||||
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showCreateFromSnippet() {
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
<!-- Create folder -->
|
||||
<div class="umb-pane" ng-if="vm.creatingFolder">
|
||||
<form novalidate name="createFolderForm"
|
||||
ng-submit="vm.createFolder()"
|
||||
val-form-manager>
|
||||
ng-submit="vm.createFolder(createFolderForm)"
|
||||
val-form-manager>
|
||||
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
<div ng-show="vm.createFolderError">
|
||||
<h5 class="text-error">{{vm.createFolderError.errorMsg}}</h5>
|
||||
<p class="text-error">{{vm.createFolderError.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function ScriptsCreateController($scope, $location, navigationService) {
|
||||
function ScriptsCreateController($scope, $location, navigationService, formHelper, codefileResource, localizationService, appState) {
|
||||
|
||||
var vm = this;
|
||||
var node = $scope.dialogOptions.currentNode;
|
||||
var localizeCreateFolder = localizationService.localize("defaultdialog_createFolder");
|
||||
|
||||
vm.creatingFolder = false;
|
||||
vm.folderName = "";
|
||||
vm.createFolderError = "";
|
||||
vm.fileExtension = "";
|
||||
|
||||
vm.createFile = createFile;
|
||||
@@ -23,8 +25,40 @@
|
||||
vm.creatingFolder = true;
|
||||
}
|
||||
|
||||
function createFolder() {
|
||||
|
||||
function createFolder(form) {
|
||||
|
||||
if (formHelper.submitForm({scope: $scope, formCtrl: form, statusMessage: localizeCreateFolder})) {
|
||||
|
||||
codefileResource.createContainer("scripts", node.id, vm.folderName).then(function (saved) {
|
||||
|
||||
navigationService.hideMenu();
|
||||
|
||||
navigationService.syncTree({
|
||||
tree: "scripts",
|
||||
path: saved.path,
|
||||
forceReload: true,
|
||||
activate: true
|
||||
});
|
||||
|
||||
formHelper.resetForm({
|
||||
scope: $scope
|
||||
});
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
|
||||
}, function(err) {
|
||||
|
||||
vm.createFolderError = err;
|
||||
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
|
||||
<div class="umb-pane" ng-if="vm.creatingFolder">
|
||||
<form novalidate name="createFolderForm"
|
||||
ng-submit="vm.createFolder()"
|
||||
ng-submit="vm.createFolder(createFolderForm)"
|
||||
val-form-manager>
|
||||
|
||||
<div ng-show="error">
|
||||
<h5 class="text-error">{{error.errorMsg}}</h5>
|
||||
<p class="text-error">{{error.data.message}}</p>
|
||||
<div ng-show="vm.createFolderError">
|
||||
<h5 class="text-error">{{vm.createFolderError.errorMsg}}</h5>
|
||||
<p class="text-error">{{vm.createFolderError.data.message}}</p>
|
||||
</div>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
<!--Settings-->
|
||||
<add initialize="true" sortOrder="0" alias="documentTypes" application="settings" title="Document Types" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.ContentTypeTreeController, umbraco" />
|
||||
<add application="settings" alias="templates" title="Templates" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.TemplatesTreeController, umbraco" initialize="true" sortOrder="1" />
|
||||
<add application="settings" alias="partialViews" title="Partial Views" silent="false" initialize="true" iconClosed="icon-folder" iconOpen="icon-folder" type="Umbraco.Web.Trees.PartialViewsTree, umbraco" sortOrder="2" />
|
||||
<add application="settings" alias="partialViews" title="Partial Views" silent="false" initialize="true" iconClosed="icon-folder" iconOpen="icon-folder" type="Umbraco.Web.Trees.PartialViewsTreeController, umbraco" sortOrder="2" />
|
||||
<add application="settings" alias="stylesheets" title="Stylesheets" type="umbraco.loadStylesheets, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="3" />
|
||||
<add application="settings" alias="stylesheetProperty" title="Stylesheet Property" type="umbraco.loadStylesheetProperty, umbraco" iconClosed="" iconOpen="" initialize="false" sortOrder="0" />
|
||||
<add application="settings" alias="scripts" title="Scripts" type="umbraco.loadScripts, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4" />
|
||||
<add application="settings" alias="scripts" title="Scripts" type="Umbraco.Web.Trees.ScriptTreeController, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4" />
|
||||
<add application="settings" alias="languages" title="Languages" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.LanguageTreeController, umbraco" sortOrder="5" />
|
||||
<add application="settings" alias="dictionary" title="Dictionary" type="umbraco.loadDictionary, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="6" />
|
||||
<add initialize="true" sortOrder="7" alias="mediaTypes" application="settings" title="Media Types" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.MediaTypeTreeController, umbraco" />
|
||||
@@ -25,7 +25,7 @@
|
||||
<add application="developer" alias="macros" title="Macros" type="umbraco.loadMacros, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="2" />
|
||||
<add application="developer" alias="relationTypes" title="Relation Types" type="umbraco.loadRelationTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4" />
|
||||
<add application="developer" alias="xslt" title="XSLT Files" type="umbraco.loadXslt, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="5" />
|
||||
<add application="developer" alias="partialViewMacros" type="Umbraco.Web.Trees.PartialViewMacrosTree, umbraco" silent="false" initialize="true" sortOrder="6" title="Partial View Macro Files" iconClosed="icon-folder" iconOpen="icon-folder" />
|
||||
<add application="developer" alias="partialViewMacros" type="Umbraco.Web.Trees.PartialViewMacrosTreeController, umbraco" silent="false" initialize="true" sortOrder="6" title="Partial View Macro Files" iconClosed="icon-folder" iconOpen="icon-folder" />
|
||||
|
||||
<!--Users-->
|
||||
<add application="users" alias="users" title="Users" type="umbraco.loadUsers, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="0" />
|
||||
|
||||
@@ -496,6 +496,8 @@
|
||||
<key alias="retry">Retry</key>
|
||||
<key alias="rights">Permissions</key>
|
||||
<key alias="search">Search</key>
|
||||
<key alias="searchNoResult">Sorry, we can not find what you are looking for</key>
|
||||
<key alias="noItemsInList">No items have been added</key>
|
||||
<key alias="server">Server</key>
|
||||
<key alias="show">Show</key>
|
||||
<key alias="showPageOnSend">Show page on Send</key>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using AutoMapper;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
@@ -56,6 +57,61 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to create a container/folder in 'partialViews', 'partialViewMacros' or 'scripts'
|
||||
/// </summary>
|
||||
/// <param name="type">'partialViews', 'partialViewMacros' or 'scripts'</param>
|
||||
/// <param name="parentId">The virtual path of the parent.</param>
|
||||
/// <param name="name">The name of the container/folder</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public CodeFileDisplay PostCreateContainer(string type, string parentId, string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type) || string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
// if the parentId is root (-1) then we just need an empty string as we are
|
||||
// creating the path below and we don't wan't -1 in the path
|
||||
if (parentId == Core.Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
parentId = string.Empty;
|
||||
}
|
||||
|
||||
name = System.Web.HttpUtility.UrlDecode(name);
|
||||
|
||||
if (parentId.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
parentId = System.Web.HttpUtility.UrlDecode(parentId);
|
||||
name = parentId.EnsureEndsWith("/") + name;
|
||||
}
|
||||
|
||||
var virtualPath = string.Empty;
|
||||
switch (type)
|
||||
{
|
||||
case Core.Constants.Trees.PartialViews:
|
||||
virtualPath = NormalizeVirtualPath(name, SystemDirectories.PartialViews);
|
||||
Services.FileService.CreatePartialViewFolder(virtualPath);
|
||||
break;
|
||||
case Core.Constants.Trees.PartialViewMacros:
|
||||
virtualPath = NormalizeVirtualPath(name, SystemDirectories.MacroPartials);
|
||||
Services.FileService.CreatePartialViewMacroFolder(virtualPath);
|
||||
break;
|
||||
case Core.Constants.Trees.Scripts:
|
||||
virtualPath = NormalizeVirtualPath(name, SystemDirectories.Scripts);
|
||||
Services.FileService.CreateScriptFolder(virtualPath);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return new CodeFileDisplay
|
||||
{
|
||||
VirtualPath = virtualPath,
|
||||
Path = Url.GetTreePathFromFilePath(virtualPath)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to get a specific file from disk via the FileService
|
||||
/// </summary>
|
||||
@@ -70,7 +126,6 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
|
||||
virtualPath = System.Web.HttpUtility.UrlDecode(virtualPath);
|
||||
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@@ -212,29 +267,46 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type) == false && string.IsNullOrWhiteSpace(virtualPath) == false)
|
||||
{
|
||||
virtualPath = System.Web.HttpUtility.UrlDecode(virtualPath);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case Core.Constants.Trees.PartialViews:
|
||||
if (IsDirectory(virtualPath, SystemDirectories.PartialViews))
|
||||
{
|
||||
Services.FileService.DeletePartialViewFolder(virtualPath);
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
if (Services.FileService.DeletePartialView(virtualPath, Security.CurrentUser.Id))
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Partial View found with the specified path");
|
||||
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Partial View or folder found with the specified path");
|
||||
|
||||
case Core.Constants.Trees.PartialViewMacros:
|
||||
if (IsDirectory(virtualPath, SystemDirectories.MacroPartials))
|
||||
{
|
||||
Services.FileService.DeletePartialViewMacroFolder(virtualPath);
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
if (Services.FileService.DeletePartialViewMacro(virtualPath, Security.CurrentUser.Id))
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Partial View Macro found with the specified path");
|
||||
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Partial View Macro or folder found with the specified path");
|
||||
|
||||
case Core.Constants.Trees.Scripts:
|
||||
if (IsDirectory(virtualPath, SystemDirectories.Scripts))
|
||||
{
|
||||
Services.FileService.DeleteScriptFolder(virtualPath);
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
if (Services.FileService.GetScriptByName(virtualPath) != null)
|
||||
{
|
||||
Services.FileService.DeleteScript(virtualPath, Security.CurrentUser.Id);
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Script found with the specified path");
|
||||
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Script or folder found with the specified path");
|
||||
|
||||
default:
|
||||
return Request.CreateResponse(HttpStatusCode.NotFound);
|
||||
@@ -388,5 +460,12 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private bool IsDirectory(string virtualPath, string systemDirectory)
|
||||
{
|
||||
var path = IOHelper.MapPath(systemDirectory + "/" + virtualPath);
|
||||
var dirInfo = new DirectoryInfo(path);
|
||||
return dirInfo.Attributes == FileAttributes.Directory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@ using umbraco.cms.presentation.Trees;
|
||||
using umbraco.presentation.developer.packages;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
@@ -81,7 +83,14 @@ namespace Umbraco.Web.Editors
|
||||
if (pack == null) throw new ArgumentNullException("pack");
|
||||
|
||||
var refreshCache = false;
|
||||
|
||||
|
||||
var removedTemplates = new List<ITemplate>();
|
||||
var removedMacros = new List<IMacro>();
|
||||
var removedContentTypes = new List<IContentType>();
|
||||
var removedDictionaryItems = new List<IDictionaryItem>();
|
||||
var removedDataTypes = new List<IDataTypeDefinition>();
|
||||
var removedFiles = new List<string>();
|
||||
|
||||
//Uninstall templates
|
||||
foreach (var item in pack.Data.Templates.ToArray())
|
||||
{
|
||||
@@ -90,6 +99,7 @@ namespace Umbraco.Web.Editors
|
||||
var found = Services.FileService.GetTemplate(nId);
|
||||
if (found != null)
|
||||
{
|
||||
removedTemplates.Add(found);
|
||||
ApplicationContext.Services.FileService.DeleteTemplate(found.Alias, Security.GetUserId());
|
||||
}
|
||||
pack.Data.Templates.Remove(nId.ToString());
|
||||
@@ -103,8 +113,9 @@ namespace Umbraco.Web.Editors
|
||||
var macro = Services.MacroService.GetById(nId);
|
||||
if (macro != null)
|
||||
{
|
||||
removedMacros.Add(macro);
|
||||
Services.MacroService.Delete(macro);
|
||||
}
|
||||
}
|
||||
pack.Data.Macros.Remove(nId.ToString());
|
||||
}
|
||||
|
||||
@@ -128,8 +139,9 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
//TODO: I don't think this ordering is necessary
|
||||
var orderedTypes = from contentType in contentTypes
|
||||
orderby contentType.ParentId descending, contentType.Id descending
|
||||
select contentType;
|
||||
orderby contentType.ParentId descending, contentType.Id descending
|
||||
select contentType;
|
||||
removedContentTypes.AddRange(orderedTypes);
|
||||
contentTypeService.Delete(orderedTypes);
|
||||
}
|
||||
|
||||
@@ -141,8 +153,9 @@ namespace Umbraco.Web.Editors
|
||||
var di = Services.LocalizationService.GetDictionaryItemById(nId);
|
||||
if (di != null)
|
||||
{
|
||||
removedDictionaryItems.Add(di);
|
||||
Services.LocalizationService.Delete(di);
|
||||
}
|
||||
}
|
||||
pack.Data.DictionaryItems.Remove(nId.ToString());
|
||||
}
|
||||
|
||||
@@ -154,8 +167,9 @@ namespace Umbraco.Web.Editors
|
||||
var dtd = Services.DataTypeService.GetDataTypeDefinitionById(nId);
|
||||
if (dtd != null)
|
||||
{
|
||||
removedDataTypes.Add(dtd);
|
||||
Services.DataTypeService.Delete(dtd);
|
||||
}
|
||||
}
|
||||
pack.Data.DataTypes.Remove(nId.ToString());
|
||||
}
|
||||
|
||||
@@ -196,30 +210,45 @@ namespace Umbraco.Web.Editors
|
||||
//Remove files
|
||||
foreach (var item in pack.Data.Files.ToArray())
|
||||
{
|
||||
removedFiles.Add(item.GetRelativePath());
|
||||
|
||||
//here we need to try to find the file in question as most packages does not support the tilde char
|
||||
var file = IOHelper.FindFile(item);
|
||||
if (file != null)
|
||||
{
|
||||
if (file.StartsWith("/") == false)
|
||||
file = string.Format("/{0}", file);
|
||||
|
||||
var filePath = IOHelper.MapPath(file);
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
|
||||
}
|
||||
}
|
||||
pack.Data.Files.Remove(file);
|
||||
}
|
||||
pack.Save();
|
||||
pack.Delete(Security.GetUserId());
|
||||
|
||||
|
||||
// create a summary of what was actually removed, for PackagingService.UninstalledPackage
|
||||
var summary = new UninstallationSummary
|
||||
{
|
||||
MetaData = pack.GetMetaData(),
|
||||
TemplatesUninstalled = removedTemplates,
|
||||
MacrosUninstalled = removedMacros,
|
||||
ContentTypesUninstalled = removedContentTypes,
|
||||
DictionaryItemsUninstalled = removedDictionaryItems,
|
||||
DataTypesUninstalled = removedDataTypes,
|
||||
FilesUninstalled = removedFiles,
|
||||
PackageUninstalled = true
|
||||
};
|
||||
|
||||
// trigger the UninstalledPackage event
|
||||
PackagingService.OnUninstalledPackage(new UninstallPackageEventArgs<UninstallationSummary>(summary, false));
|
||||
|
||||
//TODO: Legacy - probably not needed
|
||||
if (refreshCache)
|
||||
{
|
||||
library.RefreshContent();
|
||||
}
|
||||
}
|
||||
TreeDefinitionCollection.Instance.ReRegisterTrees();
|
||||
global::umbraco.BusinessLogic.Actions.Action.ReRegisterActionsAndHandlers();
|
||||
}
|
||||
@@ -239,8 +268,8 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
Version pckVersion;
|
||||
return Version.TryParse(pck.Data.Version, out pckVersion)
|
||||
? new {package = pck, version = pckVersion}
|
||||
: new {package = pck, version = new Version(0, 0, 0)};
|
||||
? new { package = pck, version = pckVersion }
|
||||
: new { package = pck, version = new Version(0, 0, 0) };
|
||||
})
|
||||
.Select(grouping =>
|
||||
{
|
||||
@@ -311,7 +340,7 @@ namespace Umbraco.Web.Editors
|
||||
model.UmbracoVersion = ins.RequirementsType == RequirementsType.Strict
|
||||
? string.Format("{0}.{1}.{2}", ins.RequirementsMajor, ins.RequirementsMinor, ins.RequirementsPatch)
|
||||
: string.Empty;
|
||||
|
||||
|
||||
//now we need to check for version comparison
|
||||
model.IsCompatible = true;
|
||||
if (ins.RequirementsType == RequirementsType.Strict)
|
||||
@@ -391,7 +420,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
//TODO: Currently it has to be here, it's not ideal but that's the way it is right now
|
||||
var packageTempDir = IOHelper.MapPath(SystemDirectories.Data);
|
||||
|
||||
|
||||
//ensure it's there
|
||||
Directory.CreateDirectory(packageTempDir);
|
||||
|
||||
@@ -407,14 +436,14 @@ namespace Umbraco.Web.Editors
|
||||
PopulateFromPackageData(model);
|
||||
|
||||
var validate = ValidateInstalledInternal(model.Name, model.Version);
|
||||
|
||||
|
||||
if (validate == false)
|
||||
{
|
||||
//this package is already installed
|
||||
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse(
|
||||
Services.TextService.Localize("packager/packageAlreadyInstalled")));
|
||||
Services.TextService.Localize("packager/packageAlreadyInstalled")));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -423,7 +452,7 @@ namespace Umbraco.Web.Editors
|
||||
Services.TextService.Localize("media/disallowedFileType"),
|
||||
SpeechBubbleIcon.Warning));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return model;
|
||||
@@ -445,7 +474,7 @@ namespace Umbraco.Web.Editors
|
||||
//our repo guid
|
||||
using (var our = Repository.getByGuid("65194810-1f85-11dd-bd0b-0800200c9a66"))
|
||||
{
|
||||
path = our.fetch(packageGuid, Security.CurrentUser.Id);
|
||||
path = our.fetch(packageGuid, Security.CurrentUser.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,12 +518,12 @@ namespace Umbraco.Web.Editors
|
||||
if (UmbracoVersion.Current < packageMinVersion)
|
||||
{
|
||||
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse(
|
||||
Services.TextService.Localize("packager/targetVersionMismatch", new[] {packageMinVersion.ToString()})));
|
||||
Services.TextService.Localize("packager/targetVersionMismatch", new[] { packageMinVersion.ToString() })));
|
||||
}
|
||||
}
|
||||
|
||||
model.TemporaryDirectoryPath = Path.Combine(SystemDirectories.Data, tempPath);
|
||||
model.Id = ins.CreateManifest( IOHelper.MapPath(model.TemporaryDirectoryPath), model.PackageGuid.ToString(), model.RepositoryGuid.ToString());
|
||||
model.Id = ins.CreateManifest(IOHelper.MapPath(model.TemporaryDirectoryPath), model.PackageGuid.ToString(), model.RepositoryGuid.ToString());
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http.Formatting;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Web.Trees
|
||||
/// <param name="xNode"></param>
|
||||
protected virtual void OnRenderFolderNode(ref TreeNode treeNode) { }
|
||||
|
||||
protected override Models.Trees.TreeNodeCollection GetTreeNodes(string id, System.Net.Http.Formatting.FormDataCollection queryStrings)
|
||||
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
string orgPath = "";
|
||||
string path = "";
|
||||
@@ -90,6 +90,64 @@ namespace Umbraco.Web.Trees
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
|
||||
//if root node no need to visit the filesystem so lets just create the menu and return it
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
string path;
|
||||
if (string.IsNullOrEmpty(id) == false)
|
||||
{
|
||||
var orgPath = System.Web.HttpUtility.UrlDecode(id);
|
||||
path = IOHelper.MapPath(FilePath + "/" + orgPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = IOHelper.MapPath(FilePath);
|
||||
}
|
||||
|
||||
var dirInfo = new DirectoryInfo(path);
|
||||
//check if it's a directory
|
||||
if (dirInfo.Attributes == FileAttributes.Directory)
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
|
||||
var hasChildren = dirInfo.GetFiles().Length > 0 || dirInfo.GetDirectories().Length > 0;
|
||||
//We can only delete folders if it doesn't have any children (folders or files)
|
||||
if (hasChildren == false)
|
||||
{
|
||||
//delete action
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true);
|
||||
}
|
||||
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
}
|
||||
//if it's not a directory then we only allow to delete the item
|
||||
else
|
||||
{
|
||||
//delete action
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using System.Net.Http.Formatting;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
/// <summary>
|
||||
/// Tree for displaying partial view macros in the developer app
|
||||
/// </summary>
|
||||
[Tree(Constants.Applications.Developer, "partialViewMacros", "Partial View Macro Files", sortOrder: 6)]
|
||||
/// <summary>
|
||||
/// Tree for displaying partial view macros in the developer app
|
||||
/// </summary>
|
||||
[Tree(Constants.Applications.Developer, "partialViewMacros", "Partial View Macro Files", sortOrder: 6)]
|
||||
public class PartialViewMacrosTreeController : FileSystemTreeController
|
||||
{
|
||||
protected override string FilePath
|
||||
@@ -28,37 +25,6 @@ namespace Umbraco.Web.Trees
|
||||
get { return "icon-article"; }
|
||||
}
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
if (id.EndsWith(FileSearchPattern.TrimStart("*")) == false)
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
}
|
||||
|
||||
// TODO: Wire up new delete dialog
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
return menu;
|
||||
}
|
||||
|
||||
protected override void OnRenderFileNode(ref TreeNode treeNode)
|
||||
{
|
||||
base.OnRenderFileNode(ref treeNode);
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using System.Net.Http.Formatting;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
@@ -27,37 +24,6 @@ namespace Umbraco.Web.Trees
|
||||
get { return "icon-article"; }
|
||||
}
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
if (id.EndsWith(FileSearchPattern.TrimStart("*")) == false)
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
}
|
||||
|
||||
// TODO: Wire up new delete dialog
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
return menu;
|
||||
}
|
||||
|
||||
protected override void OnRenderFileNode(ref TreeNode treeNode)
|
||||
{
|
||||
base.OnRenderFileNode(ref treeNode);
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using System.Net.Http.Formatting;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
@@ -25,37 +21,6 @@ namespace Umbraco.Web.Trees
|
||||
get { return "icon-script"; }
|
||||
}
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
if (id.EndsWith(FileSearchPattern.TrimStart("*")) == false)
|
||||
{
|
||||
//set the default to create
|
||||
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
|
||||
//create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
}
|
||||
|
||||
// TODO: Wire up new delete dialog
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
return menu;
|
||||
}
|
||||
|
||||
protected override void OnRenderFolderNode(ref TreeNode treeNode)
|
||||
{
|
||||
//TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now.
|
||||
|
||||
@@ -14,16 +14,18 @@ using Umbraco.Core.Packaging;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.BusinessLogic;
|
||||
using System.Diagnostics;
|
||||
using umbraco.cms.businesslogic.macro;
|
||||
using umbraco.cms.businesslogic.template;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace umbraco.cms.businesslogic.packager
|
||||
{
|
||||
/// <summary>
|
||||
/// The packager is a component which enables sharing of both data and functionality components between different umbraco installations.
|
||||
///
|
||||
/// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macroes/documenttypes (etc.)
|
||||
/// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macros/documenttypes (etc.)
|
||||
/// in a Xml document, along with the physical files used (images/usercontrols/xsl documents etc.)
|
||||
///
|
||||
/// Partly implemented, import of packages is done, the export is *under construction*.
|
||||
@@ -507,6 +509,7 @@ namespace umbraco.cms.businesslogic.packager
|
||||
}
|
||||
|
||||
OnPackageBusinessLogicInstalled(insPack);
|
||||
OnPackageInstalled(insPack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,6 +520,7 @@ namespace umbraco.cms.businesslogic.packager
|
||||
/// <param name="tempDir"></param>
|
||||
public void InstallCleanUp(int packageId, string tempDir)
|
||||
{
|
||||
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, true);
|
||||
@@ -814,5 +818,21 @@ namespace umbraco.cms.businesslogic.packager
|
||||
EventHandler<InstalledPackage> handler = PackageBusinessLogicInstalled;
|
||||
if (handler != null) handler(null, e);
|
||||
}
|
||||
|
||||
private void OnPackageInstalled(InstalledPackage insPack)
|
||||
{
|
||||
// getting an InstallationSummary for sending to the PackagingService.ImportedPackage event
|
||||
var fileService = ApplicationContext.Current.Services.FileService;
|
||||
var macroService = ApplicationContext.Current.Services.MacroService;
|
||||
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
|
||||
var dataTypeService = ApplicationContext.Current.Services.DataTypeService;
|
||||
var localizationService = ApplicationContext.Current.Services.LocalizationService;
|
||||
|
||||
var installationSummary = insPack.GetInstallationSummary(contentTypeService, dataTypeService, fileService, localizationService, macroService);
|
||||
installationSummary.PackageInstalled = true;
|
||||
|
||||
var args = new ImportPackageEventArgs<InstallationSummary>(installationSummary, false);
|
||||
PackagingService.OnImportedPackage(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Auditing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace umbraco.cms.businesslogic.packager {
|
||||
public class InstalledPackage
|
||||
@@ -124,5 +127,70 @@ namespace umbraco.cms.businesslogic.packager {
|
||||
if (AfterDelete != null)
|
||||
AfterDelete(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used internally for creating an InstallationSummary (used in new PackagingService) representation of this InstalledPackage object.
|
||||
/// </summary>
|
||||
/// <param name="contentTypeService"></param>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <param name="fileService"></param>
|
||||
/// <param name="localizationService"></param>
|
||||
/// <param name="macroService"></param>
|
||||
/// <returns></returns>
|
||||
internal InstallationSummary GetInstallationSummary(IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, ILocalizationService localizationService, IMacroService macroService)
|
||||
{
|
||||
var macros = TryGetIntegerIds(Data.Macros).Select(macroService.GetById).ToList();
|
||||
var templates = TryGetIntegerIds(Data.Templates).Select(fileService.GetTemplate).ToList();
|
||||
var contentTypes = TryGetIntegerIds(Data.Documenttypes).Select(contentTypeService.GetContentType).ToList();
|
||||
var dataTypes = TryGetIntegerIds(Data.DataTypes).Select(dataTypeService.GetDataTypeDefinitionById).ToList();
|
||||
var dictionaryItems = TryGetIntegerIds(Data.DictionaryItems).Select(localizationService.GetDictionaryItemById).ToList();
|
||||
var languages = TryGetIntegerIds(Data.Languages).Select(localizationService.GetLanguageById).ToList();
|
||||
|
||||
for (var i = 0; i < Data.Files.Count; i++)
|
||||
{
|
||||
var filePath = Data.Files[i];
|
||||
Data.Files[i] = filePath.GetRelativePath();
|
||||
}
|
||||
|
||||
return new InstallationSummary
|
||||
{
|
||||
ContentTypesInstalled = contentTypes,
|
||||
DataTypesInstalled = dataTypes,
|
||||
DictionaryItemsInstalled = dictionaryItems,
|
||||
FilesInstalled = Data.Files,
|
||||
LanguagesInstalled = languages,
|
||||
MacrosInstalled = macros,
|
||||
MetaData = GetMetaData(),
|
||||
TemplatesInstalled = templates,
|
||||
};
|
||||
}
|
||||
|
||||
internal MetaData GetMetaData()
|
||||
{
|
||||
return new MetaData()
|
||||
{
|
||||
AuthorName = Data.Author,
|
||||
AuthorUrl = Data.AuthorUrl,
|
||||
Control = Data.LoadControl,
|
||||
License = Data.License,
|
||||
LicenseUrl = Data.LicenseUrl,
|
||||
Name = Data.Name,
|
||||
Readme = Data.Readme,
|
||||
Url = Data.Url,
|
||||
Version = Data.Version
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<int> TryGetIntegerIds(IEnumerable<string> ids)
|
||||
{
|
||||
var intIds = new List<int>();
|
||||
foreach (var id in ids)
|
||||
{
|
||||
int parsed;
|
||||
if (int.TryParse(id, out parsed))
|
||||
intIds.Add(parsed);
|
||||
}
|
||||
return intIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,13 +72,14 @@ namespace umbraco.cms.businesslogic.propertytype
|
||||
_tabId = _propertyTypeGroup;
|
||||
}
|
||||
|
||||
//Fixed issue U4-9493 Case issues
|
||||
_sortOrder = found.sortOrder;
|
||||
_alias = found.alias;
|
||||
_name = found.name;
|
||||
_alias = found.Alias;
|
||||
_name = found.Name;
|
||||
_validationRegExp = found.validationRegExp;
|
||||
_DataTypeId = found.DataTypeId;
|
||||
_DataTypeId = found.dataTypeId;
|
||||
_contenttypeid = found.contentTypeId;
|
||||
_description = found.description;
|
||||
_description = found.Description;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user