Merge remote-tracking branch 'origin/v8/dev' into v8/feature/block-editor-list

# Conflicts:
#	src/Umbraco.Web.UI/Umbraco/js/main.controller.js
#	src/Umbraco.Web.UI/Umbraco/js/navigation.controller.js
This commit is contained in:
Niels Lyngsø
2020-03-31 17:54:10 +02:00
73 changed files with 725 additions and 339 deletions
+3
View File
@@ -100,6 +100,9 @@ src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.dev.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/canvasdesigner.*.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/navigation.controller.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.controller.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/utilities.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js
+1 -1
View File
@@ -25,7 +25,7 @@
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="ClientDependency" version="[1.9.8,1.999999)" />
<dependency id="ClientDependency" version="[1.9.9,1.999999)" />
<dependency id="ClientDependency-Mvc5" version="[1.9.3,1.999999)" />
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
<dependency id="Examine" version="[1.0.2,1.999999)" />
+3 -1
View File
@@ -22,6 +22,8 @@
# get NuGet
$cache = 4
$nuget = "$scriptTemp\nuget.exe"
# ensure the correct NuGet-source is used. This one is used by Umbraco
$nugetsourceUmbraco = "https://www.myget.org/F/umbracocore/api/v3/index.json"
if (-not $local)
{
$source = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
@@ -61,7 +63,7 @@
# get the build system
if (-not $local)
{
$params = "-OutputDirectory", $scriptTemp, "-Verbosity", "quiet", "-PreRelease"
$params = "-OutputDirectory", $scriptTemp, "-Verbosity", "quiet", "-PreRelease", "-Source", $nugetsourceUmbraco
&$nuget install Umbraco.Build @params
if (-not $?) { throw "Failed to download Umbraco.Build." }
}
+4 -1
View File
@@ -375,11 +375,14 @@
})
$nugetsourceUmbraco = "https://api.nuget.org/v3/index.json"
$ubuild.DefineMethod("RestoreNuGet",
{
Write-Host "Restore NuGet"
Write-Host "Logging to $($this.BuildTemp)\nuget.restore.log"
&$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" > "$($this.BuildTemp)\nuget.restore.log"
$params = "-Source", $nugetsourceUmbraco
&$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" > "$($this.BuildTemp)\nuget.restore.log" @params
if (-not $?) { throw "Failed to restore NuGet packages." }
})
+12 -14
View File
@@ -37,23 +37,13 @@ namespace Umbraco.Core.Cache
/// <inheritdoc />
public object Get(string key, Func<object> factory, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
{
CacheDependency dependency = null;
if (dependentFiles != null && dependentFiles.Any())
{
dependency = new CacheDependency(dependentFiles);
}
return Get(key, factory, timeout, isSliding, priority, removedCallback, dependency);
return GetInternal(key, factory, timeout, isSliding, priority, removedCallback, dependentFiles);
}
/// <inheritdoc />
public void Insert(string key, Func<object> factory, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
{
CacheDependency dependency = null;
if (dependentFiles != null && dependentFiles.Any())
{
dependency = new CacheDependency(dependentFiles);
}
Insert(key, factory, timeout, isSliding, priority, removedCallback, dependency);
InsertInternal(key, factory, timeout, isSliding, priority, removedCallback, dependentFiles);
}
#region Dictionary
@@ -103,7 +93,7 @@ namespace Umbraco.Core.Cache
#endregion
private object Get(string key, Func<object> factory, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, CacheDependency dependency = null)
private object GetInternal(string key, Func<object> factory, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
{
key = GetCacheKey(key);
@@ -163,6 +153,10 @@ namespace Umbraco.Core.Cache
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
lck.UpgradeToWriteLock();
// create a cache dependency if one is needed.
var dependency = dependentFiles != null && dependentFiles.Length > 0 ? new CacheDependency(dependentFiles) : null;
//NOTE: 'Insert' on System.Web.Caching.Cache actually does an add or update!
_cache.Insert(key, result, dependency, absolute, sliding, priority, removedCallback);
}
@@ -180,7 +174,7 @@ namespace Umbraco.Core.Cache
return value;
}
private void Insert(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, CacheDependency dependency = null)
private void InsertInternal(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
{
// NOTE - here also we must insert a Lazy<object> but we can evaluate it right now
// and make sure we don't store a null value.
@@ -197,6 +191,10 @@ namespace Umbraco.Core.Cache
try
{
_locker.EnterWriteLock();
// create a cache dependency if one is needed.
var dependency = dependentFiles != null && dependentFiles.Length > 0 ? new CacheDependency(dependentFiles) : null;
//NOTE: 'Insert' on System.Web.Caching.Cache actually does an add or update!
_cache.Insert(cacheKey, result, dependency, absolute, sliding, priority, removedCallback);
}
+2
View File
@@ -28,8 +28,10 @@ namespace Umbraco.Core
public const string UnknownUserName = "SYTEM";
public const string AdminGroupAlias = "admin";
public const string EditorGroupAlias = "editor";
public const string SensitiveDataGroupAlias = "sensitiveData";
public const string TranslatorGroupAlias = "translator";
public const string WriterGroupAlias = "writer";
public const string BackOfficeAuthenticationType = "UmbracoBackOffice";
public const string BackOfficeExternalAuthenticationType = "UmbracoExternalCookie";
@@ -171,8 +171,8 @@ namespace Umbraco.Core.Migrations.Install
private void CreateUserGroupData()
{
_database.Insert(Constants.DatabaseSchema.Tables.UserGroup, "id", false, new UserGroupDto { Id = 1, StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.AdminGroupAlias, Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F7ï", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-medal" });
_database.Insert(Constants.DatabaseSchema.Tables.UserGroup, "id", false, new UserGroupDto { Id = 2, StartMediaId = -1, StartContentId = -1, Alias = "writer", Name = "Writers", DefaultPermissions = "CAH:F", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-edit" });
_database.Insert(Constants.DatabaseSchema.Tables.UserGroup, "id", false, new UserGroupDto { Id = 3, StartMediaId = -1, StartContentId = -1, Alias = "editor", Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5Fï", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-tools" });
_database.Insert(Constants.DatabaseSchema.Tables.UserGroup, "id", false, new UserGroupDto { Id = 2, StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.WriterGroupAlias, Name = "Writers", DefaultPermissions = "CAH:F", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-edit" });
_database.Insert(Constants.DatabaseSchema.Tables.UserGroup, "id", false, new UserGroupDto { Id = 3, StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.EditorGroupAlias, Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5Fï", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-tools" });
_database.Insert(Constants.DatabaseSchema.Tables.UserGroup, "id", false, new UserGroupDto { Id = 4, StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.TranslatorGroupAlias, Name = "Translators", DefaultPermissions = "AF", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-globe" });
_database.Insert(Constants.DatabaseSchema.Tables.UserGroup, "id", false, new UserGroupDto { Id = 5, StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.SensitiveDataGroupAlias, Name = "Sensitive data", DefaultPermissions = "", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-lock" });
}
@@ -167,6 +167,7 @@ namespace Umbraco.Core.Migrations.Upgrade
.As("{0576E786-5C30-4000-B969-302B61E90CA3}");
To<FixLanguageIsoCodeLength>("{48AD6CCD-C7A4-4305-A8AB-38728AD23FC5}");
To<AddPackagesSectionAccess>("{DF470D86-E5CA-42AC-9780-9D28070E25F9}");
// finish migrating from v7 - recreate all keys and indexes
To<CreateKeysAndIndexes>("{3F9764F5-73D0-4D45-8804-1240A66E43A2}");
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class AddPackagesSectionAccess : MigrationBase
{
public AddPackagesSectionAccess(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
// Any user group which had access to the Developer section should have access to Packages
Database.Execute($@"
insert into {Constants.DatabaseSchema.Tables.UserGroup2App}
select userGroupId, '{Constants.Applications.Packages}'
from {Constants.DatabaseSchema.Tables.UserGroup2App}
where app='developer'");
}
}
}
+3 -2
View File
@@ -81,9 +81,10 @@ namespace Umbraco.Core.Models
if (propertyInfo.PropertyType.IsGenericType
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IReadOnlyCollection<>)))
{
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
//if it is a IEnumerable<>, IReadOnlyCollection<T>, IList<T> or ICollection<> we'll use a List<> since it implements them all
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
return new ClonePropertyInfo(propertyInfo) { GenericListType = genericType };
}
+27 -1
View File
@@ -50,7 +50,7 @@ namespace Umbraco.Core.Models
/// <summary>
/// Represents a property value.
/// </summary>
public class PropertyValue
public class PropertyValue : IDeepCloneable, IEquatable<PropertyValue>
{
// TODO: Either we allow change tracking at this class level, or we add some special change tracking collections to the Property
// class to deal with change tracking which variants have changed
@@ -95,6 +95,32 @@ namespace Umbraco.Core.Models
/// </summary>
public PropertyValue Clone()
=> new PropertyValue { _culture = _culture, _segment = _segment, PublishedValue = PublishedValue, EditedValue = EditedValue };
public object DeepClone() => Clone();
public override bool Equals(object obj)
{
return Equals(obj as PropertyValue);
}
public bool Equals(PropertyValue other)
{
return other != null &&
_culture == other._culture &&
_segment == other._segment &&
EqualityComparer<object>.Default.Equals(EditedValue, other.EditedValue) &&
EqualityComparer<object>.Default.Equals(PublishedValue, other.PublishedValue);
}
public override int GetHashCode()
{
var hashCode = 1885328050;
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(_culture);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(_segment);
hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(EditedValue);
hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(PublishedValue);
return hashCode;
}
}
private static readonly DelegateEqualityComparer<object> PropertyValueComparer = new DelegateEqualityComparer<object>(
@@ -23,5 +23,12 @@
/// Gets the segment.
/// </summary>
public string Segment { get; }
/// <summary>
/// Gets the segment for the content item
/// </summary>
/// <param name="contentId"></param>
/// <returns></returns>
public virtual string GetSegment(int contentId) => Segment;
}
}
@@ -3,13 +3,32 @@
public static class VariationContextAccessorExtensions
{
public static void ContextualizeVariation(this IVariationContextAccessor variationContextAccessor, ContentVariation variations, ref string culture, ref string segment)
=> variationContextAccessor.ContextualizeVariation(variations, null, ref culture, ref segment);
public static void ContextualizeVariation(this IVariationContextAccessor variationContextAccessor, ContentVariation variations, int contentId, ref string culture, ref string segment)
=> variationContextAccessor.ContextualizeVariation(variations, (int?)contentId, ref culture, ref segment);
private static void ContextualizeVariation(this IVariationContextAccessor variationContextAccessor, ContentVariation variations, int? contentId, ref string culture, ref string segment)
{
if (culture != null && segment != null) return;
// use context values
var publishedVariationContext = variationContextAccessor?.VariationContext;
if (culture == null) culture = variations.VariesByCulture() ? publishedVariationContext?.Culture : "";
if (segment == null) segment = variations.VariesBySegment() ? publishedVariationContext?.Segment : "";
if (segment == null)
{
if (variations.VariesBySegment())
{
segment = contentId == null
? publishedVariationContext?.Segment
: publishedVariationContext?.GetSegment(contentId.Value);
}
else
{
segment = "";
}
}
}
}
}
@@ -25,8 +25,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
path = path.EnsureEndsWith(".css");
if (FileSystem.FileExists(path) == false)
// if the css directory is changed, references to the old path can still exist (ie in RTE config)
// these old references will throw an error, which breaks the RTE
// try-catch here makes the request fail silently, and allows RTE to load correctly
try
{
if (FileSystem.FileExists(path) == false)
return null;
} catch
{
return null;
}
// content will be lazy-loaded when required
var created = FileSystem.GetCreated(path).UtcDateTime;
@@ -11,6 +11,9 @@ namespace Umbraco.Core.Services
IEnumerable<string> GetAllRoles();
IEnumerable<string> GetAllRoles(int memberId);
IEnumerable<string> GetAllRoles(string username);
IEnumerable<int> GetAllRolesIds();
IEnumerable<int> GetAllRolesIds(int memberId);
IEnumerable<int> GetAllRolesIds(string username);
IEnumerable<T> GetMembersInRole(string roleName);
IEnumerable<T> FindMembersInRole(string roleName, string usernameToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
bool DeleteRole(string roleName, bool throwIfBeingUsed);
@@ -331,7 +331,7 @@ namespace Umbraco.Core.Services.Implement
saveEventArgs.CanCancel = false;
scope.Events.Dispatch(Saved, this, saveEventArgs);
}
if (withIdentity == false)
return;
@@ -816,8 +816,8 @@ namespace Umbraco.Core.Services.Implement
{
//trimming username and email to make sure we have no trailing space
member.Username = member.Username.Trim();
member.Email = member.Email.Trim();
member.Email = member.Email.Trim();
using (var scope = ScopeProvider.CreateScope())
{
var saveEventArgs = new SaveEventArgs<IMember>(member);
@@ -971,6 +971,35 @@ namespace Umbraco.Core.Services.Implement
}
}
public IEnumerable<int> GetAllRolesIds()
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.MemberTree);
return _memberGroupRepository.GetMany().Select(x => x.Id).Distinct();
}
}
public IEnumerable<int> GetAllRolesIds(int memberId)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.MemberTree);
var result = _memberGroupRepository.GetMemberGroupsForMember(memberId);
return result.Select(x => x.Id).Distinct();
}
}
public IEnumerable<int> GetAllRolesIds(string username)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
scope.ReadLock(Constants.Locks.MemberTree);
var result = _memberGroupRepository.GetMemberGroupsForMember(username);
return result.Select(x => x.Id).Distinct();
}
}
public IEnumerable<IMember> GetMembersInRole(string roleName)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
@@ -1241,7 +1270,7 @@ namespace Umbraco.Core.Services.Implement
/// Exports a member.
/// </summary>
/// <remarks>
/// This is internal for now and is used to export a member in the member editor,
/// This is internal for now and is used to export a member in the member editor,
/// it will raise an event so that auditing logs can be created.
/// </remarks>
internal MemberExportModel ExportMember(Guid key)
@@ -372,7 +372,7 @@ namespace Umbraco.Core.Services.Implement
/// <returns></returns>
public string GetDefaultMemberType()
{
return "writer";
return Constants.Security.WriterGroupAlias;
}
/// <summary>
+15
View File
@@ -79,6 +79,21 @@ namespace Umbraco.Core
}
/// <summary>
/// Determines the extension of the path or URL
/// </summary>
/// <param name="file"></param>
/// <returns>Extension of the file</returns>
public static string GetFileExtension(this string file)
{
//Find any characters between the last . and the start of a query string or the end of the string
const string pattern = @"(?<extension>\.[^\.\?]+)(\?.*|$)";
var match = Regex.Match(file, pattern);
return match.Success
? match.Groups["extension"].Value
: string.Empty;
}
/// <summary>
/// Based on the input string, this will detect if the string is a JS path or a JS snippet.
/// If a path cannot be determined, then it is assumed to be a snippet the original text is returned
+1
View File
@@ -261,6 +261,7 @@
<Compile Include="Manifest\ManifestFilterCollectionBuilder.cs" />
<Compile Include="Mapping\MapperContext.cs" />
<Compile Include="Migrations\Upgrade\Common\DeleteKeysAndIndexes.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\AddPackagesSectionAccess.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\ContentPickerPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\DecimalPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\IPreValueMigrator.cs" />
+1 -1
View File
@@ -96,7 +96,7 @@ namespace Umbraco.Tests.Cache
return "";
});
Assert.AreEqual(counter, 1);
Assert.AreEqual(1, counter);
}
@@ -16,7 +16,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
[Test]
public void EmailAddress()
{
Assert.AreEqual(SettingsSection.Content.NotificationEmailAddress, "robot@umbraco.dk");
Assert.AreEqual("robot@umbraco.dk", SettingsSection.Content.NotificationEmailAddress);
}
[Test]
public virtual void DisableHtmlEmail()
@@ -27,17 +27,17 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
[Test]
public virtual void Can_Set_Multiple()
{
Assert.AreEqual(SettingsSection.Content.Error404Collection.Count(), 3);
Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(0).Culture, "default");
Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(0).ContentId, 1047);
Assert.AreEqual(3, SettingsSection.Content.Error404Collection.Count());
Assert.AreEqual("default", SettingsSection.Content.Error404Collection.ElementAt(0).Culture);
Assert.AreEqual(1047, SettingsSection.Content.Error404Collection.ElementAt(0).ContentId);
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentId);
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentKey);
Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(1).Culture, "en-US");
Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(1).ContentXPath, "$site/error [@name = 'error']");
Assert.AreEqual("en-US", SettingsSection.Content.Error404Collection.ElementAt(1).Culture);
Assert.AreEqual("$site/error [@name = 'error']", SettingsSection.Content.Error404Collection.ElementAt(1).ContentXPath);
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentId);
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentKey);
Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(2).Culture, "en-UK");
Assert.AreEqual(SettingsSection.Content.Error404Collection.ElementAt(2).ContentKey, new Guid("8560867F-B88F-4C74-A9A4-679D8E5B3BFC"));
Assert.AreEqual("en-UK", SettingsSection.Content.Error404Collection.ElementAt(2).Culture);
Assert.AreEqual(new Guid("8560867F-B88F-4C74-A9A4-679D8E5B3BFC"), SettingsSection.Content.Error404Collection.ElementAt(2).ContentKey);
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentKey);
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentId);
}
@@ -47,23 +47,23 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
{
Assert.IsTrue(SettingsSection.Content.ImageFileTypes.All(x => "jpeg,jpg,gif,bmp,png,tiff,tif".Split(',').Contains(x)));
}
[Test]
public virtual void ImageAutoFillProperties()
{
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.Count(), 2);
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).Alias, "umbracoFile");
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).WidthFieldAlias, "umbracoWidth");
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).HeightFieldAlias, "umbracoHeight");
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).LengthFieldAlias, "umbracoBytes");
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).ExtensionFieldAlias, "umbracoExtension");
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).Alias, "umbracoFile2");
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).WidthFieldAlias, "umbracoWidth2");
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).HeightFieldAlias, "umbracoHeight2");
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).LengthFieldAlias, "umbracoBytes2");
Assert.AreEqual(SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).ExtensionFieldAlias, "umbracoExtension2");
Assert.AreEqual(2, SettingsSection.Content.ImageAutoFillProperties.Count());
Assert.AreEqual("umbracoFile", SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).Alias);
Assert.AreEqual("umbracoWidth", SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).WidthFieldAlias);
Assert.AreEqual("umbracoHeight", SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).HeightFieldAlias);
Assert.AreEqual("umbracoBytes", SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).LengthFieldAlias);
Assert.AreEqual("umbracoExtension", SettingsSection.Content.ImageAutoFillProperties.ElementAt(0).ExtensionFieldAlias);
Assert.AreEqual("umbracoFile2", SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).Alias);
Assert.AreEqual("umbracoWidth2", SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).WidthFieldAlias);
Assert.AreEqual("umbracoHeight2", SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).HeightFieldAlias);
Assert.AreEqual("umbracoBytes2", SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).LengthFieldAlias);
Assert.AreEqual("umbracoExtension2", SettingsSection.Content.ImageAutoFillProperties.ElementAt(1).ExtensionFieldAlias);
}
[Test]
public void PreviewBadge()
{
@@ -116,7 +116,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
Debug.WriteLine("AllowedContainsExtension: {0}", allowedContainsExtension);
Debug.WriteLine("DisallowedContainsExtension: {0}", disallowedContainsExtension);
Assert.AreEqual(SettingsSection.Content.IsFileAllowedForUpload(extension), expected);
Assert.AreEqual(expected, SettingsSection.Content.IsFileAllowedForUpload(extension));
}
}
}
@@ -16,7 +16,7 @@ namespace Umbraco.Tests.CoreThings
var xmlNode = cdata.GetXmlNode(xdoc);
Assert.AreEqual(xmlNode.InnerText, "hello world");
Assert.AreEqual("hello world", xmlNode.InnerText);
}
[Test]
@@ -27,7 +27,7 @@ namespace Umbraco.Tests.CoreThings
var xmlNode = cdata.GetXmlNode(xdoc);
Assert.AreEqual(xmlNode.InnerText, "hello world");
Assert.AreEqual("hello world", xmlNode.InnerText);
}
[Test]
@@ -41,7 +41,7 @@ namespace Umbraco.Tests.CoreThings
var xmlNode = cdata.GetXmlNode(xdoc);
Assert.AreEqual(xmlNode.InnerText, "hello world");
Assert.AreEqual("hello world", xmlNode.InnerText);
Assert.AreEqual(xml, xdoc.OuterXml);
}
}
+40 -33
View File
@@ -24,7 +24,6 @@ using Umbraco.Web.PropertyEditors;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class ContentTests : UmbracoTestBase
{
@@ -42,7 +41,7 @@ namespace Umbraco.Tests.Models
// all this is required so we can validate properties...
var editor = new TextboxPropertyEditor(Mock.Of<ILogger>()) { Alias = "test" };
Composition.Register(_ => new DataEditorCollection(new [] { editor }));
Composition.Register(_ => new DataEditorCollection(new[] { editor }));
Composition.Register<PropertyEditorCollection>();
var dataType = Mock.Of<IDataType>();
Mock.Get(dataType).Setup(x => x.Configuration).Returns(() => new object());
@@ -55,7 +54,7 @@ namespace Umbraco.Tests.Models
var mediaTypeService = Mock.Of<IMediaTypeService>();
var memberTypeService = Mock.Of<IMemberTypeService>();
Composition.Register(_ => ServiceContext.CreatePartial(dataTypeService: dataTypeService, contentTypeBaseServiceProvider: new ContentTypeBaseServiceProvider(_contentTypeService, mediaTypeService, memberTypeService)));
}
[Test]
@@ -458,7 +457,7 @@ namespace Umbraco.Tests.Models
Assert.IsTrue(prop.WasPropertyDirty("Id"));
}
Assert.IsTrue(content.WasPropertyDirty("CultureInfos"));
foreach(var culture in content.CultureInfos)
foreach (var culture in content.CultureInfos)
{
Assert.IsTrue(culture.WasDirty());
Assert.IsTrue(culture.WasPropertyDirty("Name"));
@@ -539,7 +538,7 @@ namespace Umbraco.Tests.Models
var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1);
// Act
content.PropertyValues(new { title = "This is the new title"});
content.PropertyValues(new { title = "This is the new title" });
// Assert
Assert.That(content.Properties.Any(), Is.True);
@@ -603,13 +602,13 @@ namespace Umbraco.Tests.Models
// Act
contentType.PropertyGroups["Content"].PropertyTypes.Add(new PropertyType("test", ValueStorageType.Ntext, "subtitle")
{
Name = "Subtitle",
Description = "Optional subtitle",
Mandatory = false,
SortOrder = 3,
DataTypeId = -88
});
{
Name = "Subtitle",
Description = "Optional subtitle",
Mandatory = false,
SortOrder = 3,
DataTypeId = -88
});
// Assert
Assert.That(contentType.PropertyGroups["Content"].PropertyTypes.Count, Is.EqualTo(3));
@@ -626,9 +625,13 @@ namespace Umbraco.Tests.Models
// Act
var propertyType = new PropertyType("test", ValueStorageType.Ntext, "subtitle")
{
Name = "Subtitle", Description = "Optional subtitle", Mandatory = false, SortOrder = 3, DataTypeId = -88
};
{
Name = "Subtitle",
Description = "Optional subtitle",
Mandatory = false,
SortOrder = 3,
DataTypeId = -88
};
contentType.PropertyGroups["Content"].PropertyTypes.Add(propertyType);
var newProperty = new Property(propertyType);
newProperty.SetValue("This is a subtitle Test");
@@ -650,14 +653,14 @@ namespace Umbraco.Tests.Models
// Act
var propertyType = new PropertyType("test", ValueStorageType.Ntext, "subtitle")
{
Name = "Subtitle",
Description = "Optional subtitle",
Mandatory = false,
SortOrder = 3,
DataTypeId = -88
};
var propertyGroup = new PropertyGroup(true) { Name = "Test Group", SortOrder = 3};
{
Name = "Subtitle",
Description = "Optional subtitle",
Mandatory = false,
SortOrder = 3,
DataTypeId = -88
};
var propertyGroup = new PropertyGroup(true) { Name = "Test Group", SortOrder = 3 };
propertyGroup.PropertyTypes.Add(propertyType);
contentType.PropertyGroups.Add(propertyGroup);
var newProperty = new Property(propertyType);
@@ -681,9 +684,13 @@ namespace Umbraco.Tests.Models
// Act - note that the PropertyType's properties like SortOrder is not updated through the Content object
var propertyType = new PropertyType("test", ValueStorageType.Ntext, "title")
{
Name = "Title", Description = "Title description added", Mandatory = false, SortOrder = 10, DataTypeId = -88
};
{
Name = "Title",
Description = "Title description added",
Mandatory = false,
SortOrder = 10,
DataTypeId = -88
};
content.Properties.Add(new Property(propertyType));
// Assert
@@ -911,13 +918,13 @@ namespace Umbraco.Tests.Models
// Act
var propertyType = new PropertyType("test", ValueStorageType.Ntext, "subtitle")
{
Name = "Subtitle",
Description = "Optional subtitle",
Mandatory = false,
SortOrder = 3,
DataTypeId = -88
};
{
Name = "Subtitle",
Description = "Optional subtitle",
Mandatory = false,
SortOrder = 3,
DataTypeId = -88
};
contentType.PropertyGroups["Content"].PropertyTypes.Add(propertyType);
// Assert
+63
View File
@@ -0,0 +1,63 @@
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Tests.Testing;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class PropertyTests : UmbracoTestBase
{
[Test]
public void Can_Deep_Clone()
{
// needs to be within collection to support publishing
var ptCollection = new PropertyTypeCollection(true, new[] {new PropertyType("TestPropertyEditor", ValueStorageType.Nvarchar, "test")
{
Id = 3,
CreateDate = DateTime.Now,
DataTypeId = 5,
PropertyEditorAlias = "propTest",
Description = "testing",
Key = Guid.NewGuid(),
Mandatory = true,
Name = "Test",
PropertyGroupId = new Lazy<int>(() => 11),
SortOrder = 9,
UpdateDate = DateTime.Now,
ValidationRegExp = "xxxx",
ValueStorageType = ValueStorageType.Nvarchar
}});
var property = new Property(123, ptCollection[0])
{
CreateDate = DateTime.Now,
Id = 4,
Key = Guid.NewGuid(),
UpdateDate = DateTime.Now
};
property.SetValue("hello");
property.PublishValues();
var clone = (Property)property.DeepClone();
Assert.AreNotSame(clone, property);
Assert.AreNotSame(clone.Values, property.Values);
Assert.AreNotSame(property.PropertyType, clone.PropertyType);
for (int i = 0; i < property.Values.Count; i++)
{
Assert.AreNotSame(property.Values.ElementAt(i), clone.Values.ElementAt(i));
}
//This double verifies by reflection
var allProps = clone.GetType().GetProperties();
foreach (var propertyInfo in allProps)
{
Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(property, null));
}
}
}
}
@@ -1693,7 +1693,7 @@ namespace Umbraco.Tests.Persistence
{
Assert.IsTrue(testReader.Read());
Assert.AreEqual(testReader.Depth, 0);
Assert.AreEqual(0, testReader.Depth);
}
}
@@ -2067,7 +2067,7 @@ namespace Umbraco.Tests.Persistence
{
Assert.IsTrue(testReader.Read());
Assert.AreEqual(testReader.RecordsAffected, -1);
Assert.AreEqual(-1, testReader.RecordsAffected);
}
}
@@ -294,15 +294,13 @@ namespace Umbraco.Tests.Persistence.Repositories
stylesheet = repository.Get("missing.css");
Assert.IsNull(stylesheet);
// fixed in 7.3 - 7.2.8 used to...
Assert.Throws<UnauthorizedAccessException>(() =>
{
stylesheet = repository.Get("\\test-path-4.css"); // outside the filesystem, does not exist
});
Assert.Throws<UnauthorizedAccessException>(() =>
{
stylesheet = repository.Get("../packages.config"); // outside the filesystem, exists
});
// #7713 changes behaviour to return null when outside the filesystem
// to accomodate changing the CSS path and not flooding the backoffice with errors
stylesheet = repository.Get("\\test-path-4.css"); // outside the filesystem, does not exist
Assert.IsNull(stylesheet);
stylesheet = repository.Get("../packages.config"); // outside the filesystem, exists
Assert.IsNull(stylesheet);
}
}
@@ -1,9 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
@@ -27,7 +25,6 @@ using Umbraco.Web.Cache;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.PublishedCache.NuCache;
using Umbraco.Web.PublishedCache.NuCache.DataSource;
using Umbraco.Web.PublishedCache.NuCache.Snap;
namespace Umbraco.Tests.PublishedContent
{
@@ -1312,6 +1309,18 @@ namespace Umbraco.Tests.PublishedContent
AssertLinkedNode(child3.contentNode, 1, 3, -1, -1, -1);
}
[Test]
public void MultipleCacheIteration()
{
//see https://github.com/umbraco/Umbraco-CMS/issues/7798
this.Init(this.GetInvariantKits());
var snapshot = this._snapshotService.CreatePublishedSnapshot(previewToken: null);
this._snapshotAccessor.PublishedSnapshot = snapshot;
var items = snapshot.Content.GetByXPath("/root/itype");
Assert.AreEqual(items.Count(), items.Count());
}
private void AssertLinkedNode(ContentNode node, int parent, int prevSibling, int nextSibling, int firstChild, int lastChild)
{
Assert.AreEqual(parent, node.ParentContentId);
@@ -1811,7 +1811,7 @@ namespace Umbraco.Tests.Services
ServiceContext.ContentService.Save(content2, Constants.Security.SuperUserId);
Assert.IsTrue(ServiceContext.ContentService.SaveAndPublish(content2, userId: 0).Success);
var editorGroup = ServiceContext.UserService.GetUserGroupByAlias("editor");
var editorGroup = ServiceContext.UserService.GetUserGroupByAlias(Constants.Security.EditorGroupAlias);
editorGroup.StartContentId = content1.Id;
ServiceContext.UserService.Save(editorGroup);
@@ -1890,6 +1890,49 @@ namespace Umbraco.Tests.Services
//Assert.AreNotEqual(content.Name, copy.Name);
}
[Test]
public void Can_Copy_And_Modify_Content_With_Events()
{
// see https://github.com/umbraco/Umbraco-CMS/issues/5513
TypedEventHandler<IContentService, CopyEventArgs<IContent>> copying = (sender, args) =>
{
args.Copy.SetValue("title", "1");
args.Original.SetValue("title", "2");
};
TypedEventHandler<IContentService, CopyEventArgs<IContent>> copied = (sender, args) =>
{
var copyVal = args.Copy.GetValue<string>("title");
var origVal = args.Original.GetValue<string>("title");
Assert.AreEqual("1", copyVal);
Assert.AreEqual("2", origVal);
};
try
{
var contentService = ServiceContext.ContentService;
ContentService.Copying += copying;
ContentService.Copied += copied;
var contentType = MockedContentTypes.CreateSimpleContentType();
ServiceContext.ContentTypeService.Save(contentType);
var content = MockedContent.CreateSimpleContent(contentType);
content.SetValue("title", "New Value");
contentService.Save(content);
var copy = contentService.Copy(content, content.ParentId, false, Constants.Security.SuperUserId);
Assert.AreEqual("1", copy.GetValue("title"));
}
finally
{
ContentService.Copying -= copying;
ContentService.Copied -= copied;
}
}
[Test]
public void Can_Copy_Recursive()
{
@@ -197,7 +197,17 @@ namespace Umbraco.Tests.Services
Assert.AreEqual(3, found.Count());
}
[Test]
public void Can_Get_All_Roles_IDs()
{
ServiceContext.MemberService.AddRole("MyTestRole1");
ServiceContext.MemberService.AddRole("MyTestRole2");
ServiceContext.MemberService.AddRole("MyTestRole3");
var found = ServiceContext.MemberService.GetAllRolesIds();
Assert.AreEqual(3, found.Count());
}
[Test]
public void Can_Get_All_Roles_By_Member_Id()
{
@@ -216,7 +226,24 @@ namespace Umbraco.Tests.Services
Assert.AreEqual(2, memberRoles.Count());
}
[Test]
public void Can_Get_All_Roles_Ids_By_Member_Id()
{
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
ServiceContext.MemberTypeService.Save(memberType);
IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test");
ServiceContext.MemberService.Save(member);
ServiceContext.MemberService.AddRole("MyTestRole1");
ServiceContext.MemberService.AddRole("MyTestRole2");
ServiceContext.MemberService.AddRole("MyTestRole3");
ServiceContext.MemberService.AssignRoles(new[] { member.Id }, new[] { "MyTestRole1", "MyTestRole2" });
var memberRoles = ServiceContext.MemberService.GetAllRolesIds(member.Id);
Assert.AreEqual(2, memberRoles.Count());
}
[Test]
public void Can_Get_All_Roles_By_Member_Username()
{
@@ -70,6 +70,24 @@ namespace Umbraco.Tests.Strings
Assert.AreEqual(stripped, result);
}
[TestCase("../wtf.js?x=wtf", ".js")]
[TestCase(".htaccess", ".htaccess")]
[TestCase("path/to/file/image.png", ".png")]
[TestCase("c:\\abc\\def\\ghi.jkl", ".jkl")]
[TestCase("/root/folder.name/file.ext", ".ext")]
[TestCase("http://www.domain.com/folder/name/file.txt", ".txt")]
[TestCase("i/don't\\have\\an/extension", "")]
[TestCase("https://some.where/path/to/file.ext?query=this&more=that", ".ext")]
[TestCase("double_query.string/file.ext?query=abc?something.else", ".ext")]
[TestCase("test.tar.gz", ".gz")]
[TestCase("wierd.file,but._legal", "._legal")]
[TestCase("one_char.x", ".x")]
public void Get_File_Extension(string input, string result)
{
var extension = input.GetFileExtension();
Assert.AreEqual(result, extension);
}
[TestCase("'+alert(1234)+'", "+alert1234+")]
[TestCase("'+alert(56+78)+'", "+alert56+78+")]
[TestCase("{{file}}", "file")]
+1
View File
@@ -142,6 +142,7 @@
<Compile Include="Models\CultureImpactTests.cs" />
<Compile Include="Models\ImageProcessorImageUrlGeneratorTest.cs" />
<Compile Include="Models\PathValidationTests.cs" />
<Compile Include="Models\PropertyTests.cs" />
<Compile Include="Models\VariationTests.cs" />
<Compile Include="Persistence\Mappers\MapperTestBase.cs" />
<Compile Include="Persistence\Repositories\DocumentRepositoryTest.cs" />
@@ -27,7 +27,7 @@ namespace Umbraco.Tests.Web.AngularIntegration
string cookieToken, headerToken;
AngularAntiForgeryHelper.GetTokens(out cookieToken, out headerToken);
Assert.AreEqual(true, AngularAntiForgeryHelper.ValidateTokens(cookieToken, headerToken));
Assert.IsTrue(AngularAntiForgeryHelper.ValidateTokens(cookieToken, headerToken));
}
}
@@ -45,7 +45,7 @@ namespace Umbraco.Tests.Web.AngularIntegration
string cookieToken, headerToken;
AngularAntiForgeryHelper.GetTokens(out cookieToken, out headerToken);
Assert.AreEqual(true, AngularAntiForgeryHelper.ValidateTokens(cookieToken, headerToken));
Assert.IsTrue(AngularAntiForgeryHelper.ValidateTokens(cookieToken, headerToken));
}
}
+2 -2
View File
@@ -19,10 +19,10 @@
"tinyMCE": false,
"FileReader": false,
"Umbraco": false,
"Utilities": false,
"window": false,
"LazyLoad": false,
"ActiveXObject": false,
"Bloodhound": false
}
}
}
+2 -2
View File
@@ -34,9 +34,9 @@ module.exports = {
installer: { files: "./src/installer/**/*.js", out: "umbraco.installer.js" },
filters: { files: "./src/common/filters/**/*.js", out: "umbraco.filters.js" },
resources: { files: "./src/common/resources/**/*.js", out: "umbraco.resources.js" },
services: { files: "./src/common/services/**/*.js", out: "umbraco.services.js" },
services: { files: ["./src/common/services/**/*.js", "./src/utilities.js"], out: "umbraco.services.js" },
security: { files: "./src/common/interceptors/**/*.js", out: "umbraco.interceptors.js" },
//the controllers for views
controllers: {
files: [
+33 -33
View File
@@ -876,9 +876,9 @@
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
"version": "5.7.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
"integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
"dev": true
},
"source-map": {
@@ -1035,9 +1035,9 @@
"integrity": "sha512-M1JtZctO2Zg+1qeGUFZXtYKsyaRptqQtqpVzlj80I0NzGW9MF3um0DBuizIvQlrPYUlTdm+wcOPZpZoerkxQdA=="
},
"acorn": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
"integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
"integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==",
"dev": true
},
"acorn-jsx": {
@@ -2111,7 +2111,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"optional": true,
@@ -2127,7 +2127,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"optional": true,
@@ -2424,7 +2424,7 @@
},
"callsites": {
"version": "2.0.0",
"resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
"integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
"dev": true
},
@@ -2739,7 +2739,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -2754,7 +2754,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@@ -2966,7 +2966,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -2981,7 +2981,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@@ -3922,7 +3922,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -3937,7 +3937,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@@ -6606,7 +6606,7 @@
},
"kind-of": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
"integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
"dev": true
},
@@ -6771,9 +6771,9 @@
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
"version": "5.7.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
"integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
"dev": true
},
"source-map": {
@@ -6818,7 +6818,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
@@ -6894,7 +6894,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -6915,7 +6915,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@@ -8517,7 +8517,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -8532,7 +8532,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@@ -13107,7 +13107,7 @@
},
"pify": {
"version": "2.3.0",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
},
@@ -13782,7 +13782,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -13797,7 +13797,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@@ -14208,7 +14208,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
@@ -14230,7 +14230,7 @@
},
"kind-of": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
"integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
"dev": true
},
@@ -14818,7 +14818,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"optional": true,
@@ -15207,7 +15207,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"optional": true,
@@ -15293,7 +15293,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -15308,7 +15308,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
+1 -1
View File
@@ -50,7 +50,7 @@
"@babel/core": "7.6.4",
"@babel/preset-env": "7.6.3",
"autoprefixer": "9.6.5",
"caniuse-lite": "^1.0.30001002",
"caniuse-lite": "^1.0.30001037",
"cssnano": "4.1.10",
"fs": "0.0.2",
"gulp": "4.0.2",
@@ -12,26 +12,25 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
var sectionItemsWidth = [];
var evts = [];
var maxSections = 8;
//setup scope vars
scope.maxSections = maxSections;
scope.overflowingSections = 0;
scope.sections = [];
scope.visibleSections = 0;
scope.currentSection = appState.getSectionState("currentSection");
scope.showTray = false; //appState.getGlobalState("showTray");
scope.showTray = false;
scope.stickyNavigation = appState.getGlobalState("stickyNavigation");
scope.needTray = false;
function loadSections() {
sectionService.getSectionsForUser()
.then(function (result) {
scope.sections = result;
scope.visibleSections = scope.sections.length;
// store the width of each section so we can hide/show them based on browser width
// we store them because the sections get removed from the dom and then we
// can't tell when to show them gain
$timeout(function () {
$("#applications .sections li").each(function (index) {
$("#applications .sections li:not(:last)").each(function (index) {
sectionItemsWidth.push($(this).outerWidth());
});
});
@@ -42,25 +41,22 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
function calculateWidth() {
$timeout(function () {
//total width minus room for avatar, search, and help icon
var windowWidth = $(window).width() - 150;
var containerWidth = $(".umb-app-header").outerWidth() - $(".umb-app-header__actions").outerWidth();
var trayToggleWidth = $("#applications .sections li.expand").outerWidth();
var sectionsWidth = 0;
scope.totalSections = scope.sections.length;
scope.maxSections = maxSections;
scope.overflowingSections = scope.maxSections - scope.totalSections;
scope.needTray = scope.sections.length > scope.maxSections;
// detect how many sections we can show on the screen
for (var i = 0; i < sectionItemsWidth.length; i++) {
var sectionItemWidth = sectionItemsWidth[i];
sectionsWidth += sectionItemWidth;
if (sectionsWidth > windowWidth) {
scope.needTray = true;
scope.maxSections = i - 1;
scope.overflowingSections = scope.maxSections - scope.totalSections;
break;
if (sectionsWidth + trayToggleWidth > containerWidth) {
scope.visibleSections = i;
return;
}
}
scope.visibleSections = scope.sections.length;
});
}
@@ -134,14 +130,9 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
};
scope.currentSectionInOverflow = function () {
if (scope.overflowingSections === 0) {
return false;
}
var currentSection = scope.sections.filter(s => s.alias === scope.currentSection);
return (scope.sections.indexOf(currentSection[0]) >= scope.maxSections);
return currentSection.length > 0 && scope.sections.indexOf(currentSection[0]) > scope.visibleSections - 1;
};
loadSections();
@@ -178,11 +178,11 @@ function angularHelper($q) {
$valid: true,
$submitted: false,
$pending: undefined,
$addControl: angular.noop,
$removeControl: angular.noop,
$setValidity: angular.noop,
$setDirty: angular.noop,
$setPristine: angular.noop,
$addControl: Utilities.noop,
$removeControl: Utilities.noop,
$setValidity: Utilities.noop,
$setDirty: Utilities.noop,
$setPristine: Utilities.noop,
$name: formName
};
}
@@ -578,30 +578,12 @@ function navigationService($routeParams, $location, $q, $injector, eventsService
if (args.action.metaData["actionView"]) {
templateUrl = args.action.metaData["actionView"];
}
else {
//by convention we will look into the /views/{treetype}/{action}.html
// for example: /views/content/create.html
//we will also check for a 'packageName' for the current tree, if it exists then the convention will be:
// for example: /App_Plugins/{mypackage}/backoffice/{treetype}/create.html
else {
var treeAlias = treeService.getTreeAlias(args.node);
var packageTreeFolder = treeService.getTreePackageFolder(treeAlias);
if (!treeAlias) {
throw "Could not get tree alias for node " + args.node.id;
}
if (packageTreeFolder) {
templateUrl = Umbraco.Sys.ServerVariables.umbracoSettings.appPluginsPath +
"/" + packageTreeFolder +
"/backoffice/" + treeAlias + "/" + args.action.alias + ".html";
}
else {
templateUrl = "views/" + treeAlias + "/" + args.action.alias + ".html";
}
}
templateUrl = this.getTreeTemplateUrl(treeAlias, args.action.alias);
}
setMode("dialog");
@@ -611,6 +593,31 @@ function navigationService($routeParams, $location, $q, $injector, eventsService
}
},
/**
* @ngdoc method
* @name umbraco.services.navigationService#getTreeTemplateUrl
* @methodOf umbraco.services.navigationService
*
* @param {string} treeAlias the alias of the tree to look up
* @param {string} action the view file name
* @description
* creates the templateUrl based on treeAlias and action
* by convention we will look into the /views/{treetype}/{action}.html
* for example: /views/content/create.html
* we will also check for a 'packageName' for the current tree, if it exists then the convention will be:
* for example: /App_Plugins/{mypackage}/backoffice/{treetype}/create.html
*/
getTreeTemplateUrl: function(treeAlias, action) {
var packageTreeFolder = treeService.getTreePackageFolder(treeAlias);
if (packageTreeFolder) {
return Umbraco.Sys.ServerVariables.umbracoSettings.appPluginsPath +
"/" + packageTreeFolder +
"/backoffice/" + treeAlias + "/" + action + ".html";
}
else {
return "views/" + treeAlias + "/" + action + ".html";
}
},
/**
* @ngdoc method
@@ -365,12 +365,23 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#downloadFile
* @methodOf umbraco.resources.contentResource
*
* @description
* Downloads a file to the client using AJAX/XHR
* Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html
* See https://stackoverflow.com/a/24129082/694494
*
* @param {string} httpPath the path (url) to the resource being downloaded
* @returns {Promise} http promise object.
*/
downloadFile : function (httpPath) {
/**
* Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html
* See https://stackoverflow.com/a/24129082/694494
*/
// Use an arraybuffer
return $http.get(httpPath, { responseType: 'arraybuffer' })
.then(function (response) {
@@ -2,17 +2,16 @@ angular.module("umbraco.install").factory('installerService', function ($rootSco
var _status = {
index: 0,
current: undefined,
steps: undefined,
current: null,
steps: null,
loading: true,
progress: "100%"
};
var factTimer = undefined;
var factTimer;
var _installerModel = {
installId: undefined,
instructions: {
}
installId: null,
instructions: {}
};
//add to umbraco installer facts here
@@ -304,7 +303,7 @@ angular.module("umbraco.install").factory('installerService', function ($rootSco
},
switchToFeedback : function(){
service.status.current = undefined;
service.status.current = null;
service.status.loading = true;
service.status.configuring = false;
@@ -320,11 +319,11 @@ angular.module("umbraco.install").factory('installerService', function ($rootSco
switchToConfiguration : function(){
service.status.loading = false;
service.status.configuring = true;
service.status.feedback = undefined;
service.status.fact = undefined;
service.status.feedback = null;
service.status.fact = null;
if(factTimer){
clearInterval(factTimer);
if (factTimer) {
clearInterval(factTimer);
}
},
@@ -335,8 +334,8 @@ angular.module("umbraco.install").factory('installerService', function ($rootSco
service.status.feedback = "Redirecting you to Umbraco, please wait";
service.status.loading = false;
if(factTimer){
clearInterval(factTimer);
if (factTimer) {
clearInterval(factTimer);
}
$timeout(function(){
@@ -4,18 +4,19 @@ angular.module("umbraco.install").controller("Umbraco.Installer.DataBaseControll
$scope.invalidDbDns = false;
$scope.dbs = [
{ name: 'Microsoft SQL Server Compact (SQL CE)', id: 0},
{ name: 'Microsoft SQL Server', id: 1},
{ name: 'Microsoft SQL Server Compact (SQL CE)', id: 0 },
{ name: 'Microsoft SQL Server', id: 1 },
{ name: 'Microsoft SQL Azure', id: 3 },
{ name: 'Custom connection string', id: -1}
{ name: 'Custom connection string', id: -1 }
];
if ( installerService.status.current.model.dbType === undefined ) {
if (angular.isUndefined(installerService.status.current.model.dbType) || installerService.status.current.model.dbType === null) {
installerService.status.current.model.dbType = 0;
}
$scope.validateAndForward = function(){
if ( !$scope.checking && this.myForm.$valid ) {
$scope.validateAndForward = function() {
if (!$scope.checking && this.myForm.$valid)
{
$scope.checking = true;
$scope.invalidDbDns = false;
@@ -23,9 +24,9 @@ angular.module("umbraco.install").controller("Umbraco.Installer.DataBaseControll
$http.post(
Umbraco.Sys.ServerVariables.installApiBaseUrl + "PostValidateDatabaseConnection",
model ).then( function( response ) {
model).then(function(response) {
if ( response.data === true ) {
if (response.data === true) {
installerService.forward();
}
else {
@@ -1,5 +1,4 @@
angular.module("umbraco.install").controller("Umbraco.Installer.MachineKeyController", function ($scope, installerService) {
$scope.continue = function () {
installerService.status.current.model = true;
@@ -11,4 +10,4 @@
installerService.forward();
};
});
});
@@ -20,8 +20,9 @@
</li>
</ul>
<a href ng-click="setPackageAndContinue('00000000-0000-0000-0000-000000000000')"
class="btn btn-link btn-link-reverse">
<button type="button"
class="btn btn-link btn-link-reverse"
ng-click="setPackageAndContinue('00000000-0000-0000-0000-000000000000')">
No thanks, I do not want to install a starter website
</a>
</button>
</div>
@@ -13,14 +13,14 @@ angular.module("umbraco.install").controller("Umbraco.Install.UserController", f
$scope.passwordPattern = new RegExp(exp);
}
$scope.validateAndInstall = function(){
installerService.install();
$scope.validateAndInstall = function() {
installerService.install();
};
$scope.validateAndForward = function(){
if(this.myForm.$valid){
installerService.forward();
}
if (this.myForm.$valid) {
installerService.forward();
}
};
});
});
@@ -17,15 +17,17 @@
.umb-button-group {
.umb-button__button {
border-radius: @baseBorderRadius;
border-radius: @baseBorderRadius 0 0 @baseBorderRadius;
&:hover {
z-index: 2;
}
}
.umb-button-group__toggle {
border-radius: 0 @baseBorderRadius @baseBorderRadius 0;
border-left: 1px solid rgba(0,0,0,0.09);
margin-left: -2px;
margin-left: -1px;
padding-left: 10px;
padding-right: 10px;
}
}
@@ -1,19 +1,18 @@
/**
/**
* @ngdoc controller
* @name Umbraco.MainController
* @name Umbraco.MainController
* @function
*
* @description
* @description
* The main application controller
*
*/
function MainController($scope, $location, appState, treeService, notificationsService,
userService, historyService, updateChecker, navigationService, eventsService,
tmhDynamicLocale, localStorageService, editorService, overlayService, assetsService, tinyMceAssets) {
//the null is important because we do an explicit bool check on this in the view
$scope.authenticated = null;
$scope.authenticated = null;
$scope.touchDevice = appState.getGlobalState("touchDevice");
$scope.infiniteMode = false;
$scope.overlay = {};
+5 -39
View File
@@ -154,7 +154,7 @@ app.config(function ($routeProvider) {
//This allows us to dynamically change the template for this route since you cannot inject services into the templateUrl method.
template: "<div ng-include='templateUrl'></div>",
//This controller will execute for this route, then we replace the template dynamically based on the current tree.
controller: function ($scope, $routeParams, treeService) {
controller: function ($scope, $routeParams, navigationService) {
if (!$routeParams.method) {
$scope.templateUrl = "views/common/dashboard.html";
@@ -176,24 +176,7 @@ app.config(function ($routeProvider) {
$scope.templateUrl = "views/users/overview.html";
return;
}
// Here we need to figure out if this route is for a user's package tree and if so then we need
// to change it's convention view path to:
// /App_Plugins/{mypackage}/backoffice/{treetype}/{method}.html
// otherwise if it is a core tree we use the core paths:
// views/{treetype}/{method}.html
var packageTreeFolder = treeService.getTreePackageFolder($routeParams.tree);
if (packageTreeFolder) {
$scope.templateUrl = (Umbraco.Sys.ServerVariables.umbracoSettings.appPluginsPath +
"/" + packageTreeFolder +
"/backoffice/" + $routeParams.tree + "/" + $routeParams.method + ".html");
}
else {
$scope.templateUrl = ('views/' + $routeParams.tree + '/' + $routeParams.method + '.html');
}
$scope.templateUrl = navigationService.getTreeTemplateUrl($routeParams.tree, $routeParams.method);
},
reloadOnSearch: false,
resolve: canRoute(true)
@@ -202,30 +185,13 @@ app.config(function ($routeProvider) {
//This allows us to dynamically change the template for this route since you cannot inject services into the templateUrl method.
template: "<div ng-include='templateUrl'></div>",
//This controller will execute for this route, then we replace the template dynamically based on the current tree.
controller: function ($scope, $route, $routeParams, treeService) {
controller: function ($scope, $routeParams, navigationService) {
if (!$routeParams.tree || !$routeParams.method) {
$scope.templateUrl = "views/common/dashboard.html";
return;
}
// Here we need to figure out if this route is for a package tree and if so then we need
// to change it's convention view path to:
// /App_Plugins/{mypackage}/backoffice/{treetype}/{method}.html
// otherwise if it is a core tree we use the core paths:
// views/{treetype}/{method}.html
var packageTreeFolder = treeService.getTreePackageFolder($routeParams.tree);
if (packageTreeFolder) {
$scope.templateUrl = (Umbraco.Sys.ServerVariables.umbracoSettings.appPluginsPath +
"/" + packageTreeFolder +
"/backoffice/" + $routeParams.tree + "/" + $routeParams.method + ".html");
}
else {
$scope.templateUrl = ('views/' + $routeParams.tree + '/' + $routeParams.method + '.html');
}
$scope.templateUrl = navigationService.getTreeTemplateUrl($routeParams.tree, $routeParams.method);
},
reloadOnSearch: false,
reloadOnUrl: false,
@@ -0,0 +1,86 @@
/**
* A friendly utility collection to replace AngularJs' ng-functions
* If it doesn't exist here, it's probably available as vanilla JS
*
* Still carries a dependency on underscore, but if usages of underscore from
* elsewhere in the codebase can instead use these methods, the underscore
* dependency will be nicely abstracted and can be removed/swapped later
*
* This collection is open to extension...
*/
(function (window) {
/**
* Equivalent to angular.noop
*/
const noop = () => { };
/**
* Facade to angular.copy
*/
const copy = val => angular.copy(val);
/**
* Equivalent to angular.isArray
*/
const isArray = val => Array.isArray(val) || val instanceof Array;
/**
* Facade to angular.equals
*/
const equals = (a, b) => angular.equals(a, b);
/**
* Facade to angular.extend
* Use this with Angular objects, for vanilla JS objects, use Object.assign()
*/
const extend = (dst, src) => angular.extend(dst, src);
/**
* Equivalent to angular.isFunction
*/
const isFunction = val => typeof val === 'function';
/**
* Equivalent to angular.isUndefined
*/
const isUndefined = val => typeof val === 'undefined';
/**
* Equivalent to angular.isDefined. Inverts result of const isUndefined
*/
const isDefined = val => !isUndefined(val);
/**
* Equivalent to angular.isString
*/
const isString = val => typeof val === 'string';
/**
* Equivalent to angular.isNumber
*/
const isNumber = val => typeof val === 'number';
/**
* Equivalent to angular.isObject
*/
const isObject = val => val !== null && typeof val === 'object';
let _utilities = {
noop: noop,
copy: copy,
isArray: isArray,
equals: equals,
extend: extend,
isFunction: isFunction,
isUndefined: isUndefined,
isDefined: isDefined,
isString: isString,
isNumber: isNumber,
isObject: isObject
};
if (typeof (window.Utilities) === 'undefined') {
window.Utilities = _utilities;
}
})(window);
@@ -2,7 +2,7 @@
<div id="applications" ng-class="{faded:stickyNavigation}">
<ul class="sections" data-element="sections">
<li data-element="section-{{section.alias}}" ng-repeat="section in sections | limitTo: maxSections" ng-class="{current: section.alias == currentSection}">
<li data-element="section-{{section.alias}}" ng-repeat="section in sections | limitTo: visibleSections" ng-class="{current: section.alias == currentSection}">
<a href="#/{{section.alias}}"
ng-dblclick="sectionDblClick(section)"
ng-click="sectionClick($event, section)"
@@ -11,13 +11,13 @@
</a>
</li>
<li data-element="section-expand" class="expand" ng-class="{ 'open': showTray === true, current: currentSectionInOverflow() }" ng-show="needTray">
<li data-element="section-expand" class="expand" ng-class="{ 'open': showTray === true, current: currentSectionInOverflow() }" ng-show="visibleSections < sections.length">
<a href="#" ng-click="trayClick()" prevent-default>
<span class="section__name"><i></i><i></i><i></i></span>
<span class="section__name">&bull;&bull;&bull;</span>
</a>
<ul id="applications-tray" class="sections-tray shadow-depth-2" ng-if="showTray" on-outside-click="trayClick()">
<li ng-repeat="section in sections | limitTo: overflowingSections" ng-class="{current: section.alias == currentSection}">
<li ng-repeat="section in sections | limitTo: sections.length | limitTo: -(sections.length - visibleSections)" ng-class="{current: section.alias == currentSection}">
<a href="#/{{section.alias}}"
ng-dblclick="sectionDblClick(section)"
ng-click="sectionClick($event, section)"
@@ -325,7 +325,7 @@
/* ---------- SAVE ---------- */
function save() {
saveInternal().then(angular.noop, angular.noop);
saveInternal().then(Utilities.noop, Utilities.noop);
}
/** This internal save method performs the actual saving and returns a promise, not to be bound to any buttons but used by other bound methods */
@@ -15,7 +15,7 @@
packageResource.getAllCreated().then(createdPackages => {
vm.createdPackages = createdPackages;
}, angular.noop);
}, Utilities.noop);
}
@@ -80,7 +80,7 @@
activate: false
});
completeSave(saved);
}, angular.noop);
}, Utilities.noop);
} else {
@@ -9,6 +9,7 @@ angular.module("umbraco")
$element,
eventsService,
editorService,
overlayService,
$interpolate
) {
@@ -320,21 +321,22 @@ angular.module("umbraco")
var title = "";
localizationService.localize("grid_insertControl").then(function (value) {
title = value;
$scope.editorOverlay = {
view: "itempicker",
overlayService.open({
view: "itempicker",
filter: area.$allowedEditors.length > 15,
title: title,
availableItems: area.$allowedEditors,
event: event,
show: true,
submit: function (model) {
submit: function(model) {
if (model.selectedItem) {
$scope.addControl(model.selectedItem, area, index);
$scope.editorOverlay.show = false;
$scope.editorOverlay = null;
overlayService.close();
}
},
close: function() {
overlayService.close();
}
};
});
});
};
@@ -299,11 +299,4 @@
</div>
</div>
<umb-overlay
ng-if="editorOverlay.show"
model="editorOverlay"
view="editorOverlay.view"
position="target">
</umb-overlay>
</div>
@@ -39,8 +39,14 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.RteController",
stylesheetResource.getAll().then(function(stylesheets){
$scope.stylesheets = stylesheets;
_.each($scope.stylesheets, function (stylesheet) {
// if the CSS directory changes, previously assigned stylesheets are retained, but will not be visible
// and will throw a 404 when loading the RTE. Remove them here. Still needs to be saved...
let cssPath = Umbraco.Sys.ServerVariables.umbracoSettings.cssPath;
$scope.model.value.stylesheets = $scope.model.value.stylesheets
.filter(sheet => sheet.startsWith(cssPath));
$scope.stylesheets.forEach(stylesheet => {
// support both current format (full stylesheet path) and legacy format (stylesheet name only)
stylesheet.selected = $scope.model.value.stylesheets.indexOf(stylesheet.path) >= 0 ||$scope.model.value.stylesheets.indexOf(stylesheet.name) >= 0;
});
@@ -168,7 +168,7 @@
extendedSave(saved).then(function(result) {
//if all is good, then reset the form
formHelper.resetForm({ scope: $scope });
}, angular.noop);
}, Utilities.noop);
vm.user = _.omit(saved, "navigation");
//restore
@@ -112,7 +112,7 @@
userGroupsResource.deleteUserGroups(_.pluck(vm.selection, "id")).then(function (data) {
clearSelection();
onInit();
}, angular.noop);
}, Utilities.noop);
overlayService.close();
}
};
@@ -386,7 +386,7 @@
vm.selectedBulkUserGroups = [];
editorService.close();
clearSelection();
}, angular.noop);
}, Utilities.noop);
},
close: function () {
vm.selectedBulkUserGroups = [];
@@ -119,7 +119,7 @@
<span class="caret"></span>
</a>
<umb-dropdown class="pull-right" ng-if="vm.page.showStatusFilter" on-close="vm.page.showStatusFilter = false;">
<umb-dropdown-item ng-repeat="userState in vm.userStatesFilter | filter:{ count: '!0', key: '!All'}" style="padding: 8px 20px 8px 16px;">
<umb-dropdown-item ng-repeat="userState in vm.userStatesFilter | filter:{ key: '!All'}" ng-show="userState.count > 0" style="padding: 8px 20px 8px 16px;">
<umb-checkbox model="userState.selected"
on-change="vm.setUserStatesFilter(userState)"
text="{{ userState.name }} ({{userState.count}})">
+1 -1
View File
@@ -86,7 +86,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CSharpTest.Net.Collections" Version="14.906.1403.1082" />
<PackageReference Include="ClientDependency" Version="1.9.8" />
<PackageReference Include="ClientDependency" Version="1.9.9" />
<PackageReference Include="ClientDependency-Mvc5" Version="1.9.3" />
<PackageReference Include="Examine" Version="1.0.2" />
<PackageReference Include="ImageProcessor.Web" Version="4.10.0.100" />
@@ -1,19 +1,18 @@
/**
/**
* @ngdoc controller
* @name Umbraco.MainController
* @name Umbraco.MainController
* @function
*
* @description
* @description
* The main application controller
*
*/
function MainController($scope, $location, appState, treeService, notificationsService,
userService, historyService, updateChecker, navigationService, eventsService,
tmhDynamicLocale, localStorageService, editorService, overlayService, assetsService, tinyMceAssets) {
//the null is important because we do an explicit bool check on this in the view
$scope.authenticated = null;
$scope.authenticated = null;
$scope.touchDevice = appState.getGlobalState("touchDevice");
$scope.infiniteMode = false;
$scope.overlay = {};
@@ -20,7 +20,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods
public EmailNotificationMethod(ILocalizedTextService textService, IRuntimeState runtimeState, ILogger logger)
{
var recipientEmail = Settings["recipientEmail"]?.Value;
var recipientEmail = Settings?["recipientEmail"]?.Value;
if (string.IsNullOrWhiteSpace(recipientEmail))
{
Enabled = false;
+17 -11
View File
@@ -243,21 +243,27 @@ namespace Umbraco.Web
}
}
if (!lengthReached && currentTextLength >= length)
if (!lengthReached)
{
// if the last character added was the first of a two character unicode pair, add the second character
if (Char.IsHighSurrogate((char)ic))
if (currentTextLength == length)
{
var lowSurrogate = tr.Read();
outputtw.Write((char)lowSurrogate);
}
// if the last character added was the first of a two character unicode pair, add the second character
if (char.IsHighSurrogate((char)ic))
{
var lowSurrogate = tr.Read();
outputtw.Write((char)lowSurrogate);
}
// Reached truncate limit.
if (addElipsis)
{
outputtw.Write(hellip);
}
lengthReached = true;
// only add elipsis if current length greater than original length
if (currentTextLength > length)
{
if (addElipsis)
{
outputtw.Write(hellip);
}
lengthReached = true;
}
}
}
+13 -6
View File
@@ -40,12 +40,18 @@ namespace Umbraco.Web.Macros
#region MacroContent cache
// gets this macro content cache identifier
private string GetContentCacheIdentifier(MacroModel model, int pageId)
private string GetContentCacheIdentifier(MacroModel model, int pageId, string cultureName)
{
var id = new StringBuilder();
var alias = model.Alias;
id.AppendFormat("{0}-", alias);
//always add current culture to the key to allow variants to have different cache results
if (!string.IsNullOrEmpty(cultureName))
{
// are there any unusual culture formats we'd need to handle?
id.AppendFormat("{0}-", cultureName);
}
if (model.CacheByPage)
id.AppendFormat("{0}-", pageId);
@@ -190,7 +196,7 @@ namespace Umbraco.Web.Macros
? macroParams[key]?.ToString() ?? string.Empty
: string.Empty;
}
}
}
#endregion
#region Render/Execute
@@ -221,7 +227,8 @@ namespace Umbraco.Web.Macros
foreach (var prop in macro.Properties)
prop.Value = ParseAttribute(pageElements, prop.Value);
macro.CacheIdentifier = GetContentCacheIdentifier(macro, content.Id);
var cultureName = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
macro.CacheIdentifier = GetContentCacheIdentifier(macro, content.Id, cultureName);
// get the macro from cache if it is there
var macroContent = GetMacroContentFromCache(macro);
@@ -317,7 +324,7 @@ namespace Umbraco.Web.Macros
private Attempt<MacroContent> ExecuteMacroOfType(MacroModel model, IPublishedContent content)
{
if (model == null) throw new ArgumentNullException(nameof(model));
// ensure that we are running against a published node (ie available in XML)
// that may not be the case if the macro is embedded in a RTE of an unpublished document
@@ -453,9 +460,9 @@ namespace Umbraco.Web.Macros
return value;
}
#endregion
}
}
@@ -111,7 +111,7 @@ namespace Umbraco.Web.Models.PublishedContent
var propertyType = content.ContentType.GetPropertyType(alias);
if (propertyType != null)
{
_variationContextAccessor.ContextualizeVariation(propertyType.Variations, ref culture, ref segment);
_variationContextAccessor.ContextualizeVariation(propertyType.Variations, content.Id, ref culture, ref segment);
noValueProperty = content.GetProperty(alias);
}
@@ -168,7 +168,7 @@ namespace Umbraco.Web.Models.PublishedContent
{
culture = null;
segment = null;
_variationContextAccessor.ContextualizeVariation(propertyType.Variations, ref culture, ref segment);
_variationContextAccessor.ContextualizeVariation(propertyType.Variations, content.Id, ref culture, ref segment);
}
property = content?.GetProperty(alias);
@@ -48,7 +48,7 @@ namespace Umbraco.Web.PropertyEditors
internal static bool IsValidFileExtension(string fileName)
{
if (fileName.IndexOf('.') <= 0) return false;
var extension = new FileInfo(fileName).Extension.TrimStart(".");
var extension = fileName.GetFileExtension().TrimStart(".");
return Current.Configs.Settings().Content.IsFileAllowedForUpload(extension);
}
}
@@ -355,6 +355,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
private static IEnumerable<IPublishedContent> GetByXPath(XPathNodeIterator iterator)
{
iterator = iterator.Clone();
while (iterator.MoveNext())
{
var xnav = iterator.Current as NavigableNavigator;
@@ -90,7 +90,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// determines whether a property has value
public override bool HasValue(string culture = null, string segment = null)
{
_content.VariationContextAccessor.ContextualizeVariation(_variations, ref culture, ref segment);
_content.VariationContextAccessor.ContextualizeVariation(_variations, _content.Id, ref culture, ref segment);
var value = GetSourceValue(culture, segment);
var hasValue = PropertyType.IsValue(value, PropertyValueLevel.Source);
@@ -194,7 +194,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override object GetSourceValue(string culture = null, string segment = null)
{
_content.VariationContextAccessor.ContextualizeVariation(_variations, ref culture, ref segment);
_content.VariationContextAccessor.ContextualizeVariation(_variations, _content.Id, ref culture, ref segment);
if (culture == "" && segment == "")
return _sourceValue;
@@ -208,7 +208,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override object GetValue(string culture = null, string segment = null)
{
_content.VariationContextAccessor.ContextualizeVariation(_variations, ref culture, ref segment);
_content.VariationContextAccessor.ContextualizeVariation(_variations, _content.Id, ref culture, ref segment);
object value;
lock (_locko)
@@ -229,7 +229,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override object GetXPathValue(string culture = null, string segment = null)
{
_content.VariationContextAccessor.ContextualizeVariation(_variations, ref culture, ref segment);
_content.VariationContextAccessor.ContextualizeVariation(_variations, _content.Id, ref culture, ref segment);
lock (_locko)
{
@@ -687,7 +687,7 @@ namespace Umbraco.Web
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
/// <returns></returns>
/// <remarks>
/// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
/// This can be useful in order to return all nodes in an entire site by a type when combined with <see cref="UmbracoHelper.ContentAtRoot"/> or similar.
/// </remarks>
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(this IEnumerable<IPublishedContent> parentNodes, string docTypeAlias, string culture = null)
{
@@ -701,7 +701,7 @@ namespace Umbraco.Web
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
/// <returns></returns>
/// <remarks>
/// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
/// This can be useful in order to return all nodes in an entire site by a type when combined with <see cref="UmbracoHelper.ContentAtRoot"/> or similar.
/// </remarks>
public static IEnumerable<T> DescendantsOrSelf<T>(this IEnumerable<IPublishedContent> parentNodes, string culture = null)
where T : class, IPublishedContent
@@ -23,7 +23,7 @@ namespace Umbraco.Web.Security
string[] defaultUserGroups = null,
string defaultCulture = null)
{
_defaultUserGroups = defaultUserGroups ?? new[] { "editor" };
_defaultUserGroups = defaultUserGroups ?? new[] { Constants.Security.EditorGroupAlias };
_autoLinkExternalAccount = autoLinkExternalAccount;
_defaultCulture = defaultCulture ?? Current.Configs.Global().DefaultUILanguage;
}
@@ -32,7 +32,7 @@ namespace Umbraco.Web.Security.Providers
}
private readonly IMemberTypeService _memberTypeService;
private string _defaultMemberTypeAlias = "writer";
private string _defaultMemberTypeAlias = Constants.Security.WriterGroupAlias;
private volatile bool _hasDefaultMember = false;
private static readonly object Locker = new object();
+1 -1
View File
@@ -61,7 +61,7 @@
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ClientDependency" Version="1.9.8" />
<PackageReference Include="ClientDependency" Version="1.9.9" />
<PackageReference Include="CSharpTest.Net.Collections" Version="14.906.1403.1082" />
<PackageReference Include="Examine" Version="1.0.2" />
<PackageReference Include="HtmlAgilityPack" Version="1.8.14" />