Merge pull request #10781 from umbraco/v9/feature/merge_v8_dev_03082021
V9: Merge v8/dev 03082021
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
|
||||
namespace Umbraco.Core.Dashboards
|
||||
namespace Umbraco.Cms.Core.Configuration
|
||||
{
|
||||
public class ContentDashboardSettings
|
||||
{
|
||||
private const string DefaultContentDashboardPath = "cms";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content dashboard should be available to all users.
|
||||
/// </summary>
|
||||
|
||||
@@ -30,5 +30,7 @@ namespace Umbraco.Cms.Core.Configuration.Models
|
||||
/// </summary>
|
||||
[DefaultValue(StaticSqlPageSize)]
|
||||
public int SqlPageSize { get; set; } = StaticSqlPageSize;
|
||||
|
||||
public bool UnPublishedContentCompression { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
27
src/Umbraco.Core/Models/ContentEditing/ContentTypesByKeys.cs
Normal file
27
src/Umbraco.Core/Models/ContentEditing/ContentTypesByKeys.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Core.Models.ContentEditing
|
||||
{
|
||||
/// <summary>
|
||||
/// A model for retrieving multiple content types based on their keys.
|
||||
/// </summary>
|
||||
[DataContract(Name = "contentTypes", Namespace = "")]
|
||||
public class ContentTypesByKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// ID of the parent of the content type.
|
||||
/// </summary>
|
||||
[DataMember(Name = "parentId")]
|
||||
[Required]
|
||||
public int ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The id of every content type to get.
|
||||
/// </summary>
|
||||
[DataMember(Name = "contentTypeKeys")]
|
||||
[Required]
|
||||
public Guid[] ContentTypeKeys { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,12 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
///
|
||||
/// </remarks>
|
||||
public interface IPropertyCacheCompression
|
||||
{
|
||||
bool IsCompressed(IReadOnlyContentBase content, string propertyTypeAlias);
|
||||
{/// <summary>
|
||||
/// Whether a property on the content is/should be compressed
|
||||
/// </summary>
|
||||
/// <param name="content">The content</param>
|
||||
/// <param name="propertyTypeAlias">The property to compress or not</param>
|
||||
/// <param name="published">Whether this content is the published version</param>
|
||||
bool IsCompressed(IReadOnlyContentBase content, string propertyTypeAlias, bool published);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,13 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
public interface IPropertyCacheCompressionOptions
|
||||
{
|
||||
bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor);
|
||||
/// <summary>
|
||||
/// Whether a property on the content is/should be compressed
|
||||
/// </summary>
|
||||
/// <param name="content">The content</param>
|
||||
/// <param name="propertyType">The property to compress or not</param>
|
||||
/// <param name="dataEditor">The datatype of the property to compress or not</param>
|
||||
/// <param name="published">Whether this content is the published version</param>
|
||||
bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor, bool published);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,6 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
/// </summary>
|
||||
public sealed class NoopPropertyCacheCompressionOptions : IPropertyCacheCompressionOptions
|
||||
{
|
||||
public bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor) => false;
|
||||
public bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor, bool published) => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
@@ -16,13 +16,13 @@ namespace Umbraco.Core.PropertyEditors
|
||||
private readonly IPropertyCacheCompressionOptions _compressionOptions;
|
||||
private readonly IReadOnlyDictionary<int, IContentTypeComposition> _contentTypes;
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private readonly ConcurrentDictionary<(int contentTypeId, string propertyAlias), bool> _isCompressedCache;
|
||||
private readonly ConcurrentDictionary<(int contentTypeId, string propertyAlias, bool published), bool> _isCompressedCache;
|
||||
|
||||
public PropertyCacheCompression(
|
||||
IPropertyCacheCompressionOptions compressionOptions,
|
||||
IReadOnlyDictionary<int, IContentTypeComposition> contentTypes,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
ConcurrentDictionary<(int, string), bool> compressedStoragePropertyEditorCache)
|
||||
ConcurrentDictionary<(int, string, bool), bool> compressedStoragePropertyEditorCache)
|
||||
{
|
||||
_compressionOptions = compressionOptions;
|
||||
_contentTypes = contentTypes ?? throw new System.ArgumentNullException(nameof(contentTypes));
|
||||
@@ -30,9 +30,9 @@ namespace Umbraco.Core.PropertyEditors
|
||||
_isCompressedCache = compressedStoragePropertyEditorCache;
|
||||
}
|
||||
|
||||
public bool IsCompressed(IReadOnlyContentBase content, string alias)
|
||||
public bool IsCompressed(IReadOnlyContentBase content, string alias, bool published)
|
||||
{
|
||||
var compressedStorage = _isCompressedCache.GetOrAdd((content.ContentTypeId, alias), x =>
|
||||
var compressedStorage = _isCompressedCache.GetOrAdd((content.ContentTypeId, alias, published), x =>
|
||||
{
|
||||
if (!_contentTypes.TryGetValue(x.contentTypeId, out var ct))
|
||||
return false;
|
||||
@@ -44,7 +44,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
if (!_propertyEditors.TryGet(propertyType.PropertyEditorAlias, out var propertyEditor))
|
||||
return false;
|
||||
|
||||
return _compressionOptions.IsCompressed(content, propertyType, propertyEditor);
|
||||
return _compressionOptions.IsCompressed(content, propertyType, propertyEditor, published);
|
||||
});
|
||||
|
||||
return compressedStorage;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Compress large, non published text properties
|
||||
/// </summary>
|
||||
public class UnPublishedContentPropertyCacheCompressionOptions : IPropertyCacheCompressionOptions
|
||||
{
|
||||
public bool IsCompressed(IReadOnlyContentBase content, IPropertyType propertyType, IDataEditor dataEditor, bool published)
|
||||
{
|
||||
if (!published && propertyType.SupportsPublishing && propertyType.ValueStorageType == ValueStorageType.Ntext)
|
||||
{
|
||||
//Only compress non published content that supports publishing and the property is text
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,17 +34,6 @@ namespace Umbraco.Extensions
|
||||
public static string Localize(this ILocalizedTextService manager, string area, string alias, string[] tokens)
|
||||
=> manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture, ConvertToDictionaryVars(tokens));
|
||||
|
||||
/// <summary>
|
||||
/// Localize using the current thread culture
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="area"></param>
|
||||
/// <param name="alias"></param>
|
||||
/// <param name="tokens"></param>
|
||||
/// <returns></returns>
|
||||
public static string Localize(this ILocalizedTextService manager, string area, string alias, IDictionary<string, string> tokens = null)
|
||||
=> manager.Localize(area, alias, Thread.CurrentThread.CurrentUICulture, tokens);
|
||||
|
||||
/// <summary>
|
||||
/// Localize a key without any variables
|
||||
/// </summary>
|
||||
|
||||
@@ -59,4 +59,8 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="EmbeddedResources\**\*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="ContentEditing" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Table
|
||||
public class CreateTableOfDtoBuilder : IExecutableBuilder
|
||||
{
|
||||
private readonly IMigrationContext _context;
|
||||
|
||||
// TODO: This doesn't do anything.
|
||||
private readonly DatabaseType[] _supportedDatabaseTypes;
|
||||
|
||||
public CreateTableOfDtoBuilder(IMigrationContext context, params DatabaseType[] supportedDatabaseTypes)
|
||||
|
||||
@@ -211,7 +211,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade
|
||||
Merge()
|
||||
.To<AddCmsContentNuByteColumn>("{8DDDCD0B-D7D5-4C97-BD6A-6B38CA65752F}")
|
||||
.To<UpgradedIncludeIndexes>("{4695D0C9-0729-4976-985B-048D503665D8}")
|
||||
|
||||
.To<UpdateCmsPropertyGroupIdSeed>("{5C424554-A32D-4852-8ED1-A13508187901}")
|
||||
// to 9.0.0
|
||||
.With()
|
||||
.To<MigrateLogViewerQueriesFromFileToDb>("{22D801BA-A1FF-4539-BFCC-2139B55594F8}")
|
||||
@@ -222,6 +222,13 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade
|
||||
|
||||
//FINAL
|
||||
.As("{5060F3D2-88BE-4D30-8755-CF51F28EAD12}");
|
||||
|
||||
|
||||
// This should be safe to execute again. We need it with a new name to ensure updates from all the following has executed this step.
|
||||
// - 8.15 RC - Current state: {4695D0C9-0729-4976-985B-048D503665D8}
|
||||
// - 8.15 Final - Current state: {5C424554-A32D-4852-8ED1-A13508187901}
|
||||
// - 9.0 RC1 - Current state: {5060F3D2-88BE-4D30-8755-CF51F28EAD12}
|
||||
To<UpdateCmsPropertyGroupIdSeed>("{622E5172-42E1-4662-AD80-9504AF5A4E53}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using NPoco;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_15_0
|
||||
{
|
||||
@@ -14,12 +17,49 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_15_0
|
||||
|
||||
protected override void Migrate()
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList();
|
||||
// allow null for the `data` field
|
||||
if (DatabaseType.IsSqlCe())
|
||||
{
|
||||
// SQLCE does not support altering NTEXT, so we have to jump through some hoops to do it
|
||||
// All column ordering must remain the same as what is defined in the DTO so we need to create a temp table,
|
||||
// drop orig and then re-create/copy.
|
||||
Create.Table<ContentNuDtoTemp>(withoutKeysAndIndexes: true).Do();
|
||||
Execute.Sql($"INSERT INTO [{TempTableName}] SELECT nodeId, published, data, rv FROM [{Constants.DatabaseSchema.Tables.NodeData}]").Do();
|
||||
Delete.Table(Constants.DatabaseSchema.Tables.NodeData).Do();
|
||||
Create.Table<ContentNuDto>().Do();
|
||||
Execute.Sql($"INSERT INTO [{Constants.DatabaseSchema.Tables.NodeData}] SELECT nodeId, published, data, rv, NULL FROM [{TempTableName}]").Do();
|
||||
}
|
||||
else
|
||||
{
|
||||
AlterColumn<ContentNuDto>(Constants.DatabaseSchema.Tables.NodeData, "data");
|
||||
}
|
||||
|
||||
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList();
|
||||
AddColumnIfNotExists<ContentNuDto>(columns, "dataRaw");
|
||||
|
||||
// allow null
|
||||
AlterColumn<ContentNuDto>(Constants.DatabaseSchema.Tables.NodeData, "data");
|
||||
AlterColumn<ContentNuDto>(Constants.DatabaseSchema.Tables.NodeData, "data");
|
||||
}
|
||||
|
||||
private const string TempTableName = Constants.DatabaseSchema.TableNamePrefix + "cms" + "ContentNuTEMP";
|
||||
|
||||
[TableName(TempTableName)]
|
||||
[ExplicitColumns]
|
||||
private class ContentNuDtoTemp
|
||||
{
|
||||
[Column("nodeId")]
|
||||
public int NodeId { get; set; }
|
||||
|
||||
[Column("published")]
|
||||
public bool Published { get; set; }
|
||||
|
||||
[Column("data")]
|
||||
[SpecialDbType(SpecialDbTypes.NTEXT)]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Data { get; set; }
|
||||
|
||||
[Column("rv")]
|
||||
public long Rv { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_15_0
|
||||
{
|
||||
public class UpdateCmsPropertyGroupIdSeed : MigrationBase
|
||||
{
|
||||
public UpdateCmsPropertyGroupIdSeed(IMigrationContext context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Migrate()
|
||||
{
|
||||
if (DatabaseType.IsSqlCe())
|
||||
{
|
||||
Database.Execute(Sql("ALTER TABLE [cmsPropertyTypeGroup] ALTER COLUMN [id] IDENTITY (56,1)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
namespace Umbraco.Cms.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a media item with local crops.
|
||||
|
||||
@@ -13,10 +13,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence
|
||||
|
||||
public int BulkInsertRecords<T>(IUmbracoDatabase database, IEnumerable<T> records)
|
||||
{
|
||||
var recordsA = records.ToArray();
|
||||
if (recordsA.Length == 0) return 0;
|
||||
if (!records.Any()) return 0;
|
||||
|
||||
return BulkInsertRecordsWithCommands(database, recordsA);
|
||||
return BulkInsertRecordsWithCommands(database, records.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos
|
||||
internal class PropertyTypeGroupDto
|
||||
{
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(IdentitySeed = 12)]
|
||||
[PrimaryKeyColumn(IdentitySeed = 56)]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("contenttypeNodeId")]
|
||||
|
||||
@@ -40,9 +40,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence
|
||||
_tableDefinition = DefinitionFactory.GetTableDefinition(pd.Type, sqlSyntaxProvider);
|
||||
if (_tableDefinition == null) throw new InvalidOperationException("No table definition found for type " + pd.Type);
|
||||
|
||||
// only real columns, exclude result columns
|
||||
// only real columns, exclude result/computed columns
|
||||
// Like NPoco does: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L59
|
||||
_readerColumns = pd.Columns
|
||||
.Where(x => x.Value.ResultColumn == false)
|
||||
.Where(x => x.Value.ResultColumn == false && x.Value.ComputedColumn == false)
|
||||
.Select(x => x.Value)
|
||||
.ToArray();
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence
|
||||
/// <returns>The number of records that were inserted.</returns>
|
||||
private int BulkInsertRecordsSqlServer<T>(IUmbracoDatabase database, PocoData pocoData, IEnumerable<T> records)
|
||||
{
|
||||
// TODO: The main reason this exists is because the NPoco InsertBulk method doesn't return the number of items.
|
||||
// It is worth investigating the performance of this vs NPoco's because we use a custom BulkDataReader
|
||||
// which in theory should be more efficient than NPocos way of building up an in-memory DataTable.
|
||||
|
||||
// create command against the original database.Connection
|
||||
using (var command = database.CreateCommand(database.Connection, CommandType.Text, string.Empty))
|
||||
{
|
||||
@@ -50,7 +54,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence
|
||||
var syntax = database.SqlContext.SqlSyntax as SqlServerSyntaxProvider;
|
||||
if (syntax == null) throw new NotSupportedException("SqlSyntax must be SqlServerSyntaxProvider.");
|
||||
|
||||
using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction) { BulkCopyTimeout = 10000, DestinationTableName = tableName })
|
||||
using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction)
|
||||
{
|
||||
BulkCopyTimeout = 0, // 0 = no bulk copy timeout. If a timeout occurs it will be an connection/command timeout.
|
||||
DestinationTableName = tableName,
|
||||
// be consistent with NPoco: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L50
|
||||
BatchSize = 4096
|
||||
})
|
||||
using (var bulkReader = new PocoDataDataReader<T, SqlServerSyntaxProvider>(records, pocoData, syntax))
|
||||
{
|
||||
//we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters
|
||||
|
||||
@@ -17,13 +17,12 @@ namespace Umbraco.Cms.Persistence.SqlCe
|
||||
|
||||
public int BulkInsertRecords<T>(IUmbracoDatabase database, IEnumerable<T> records)
|
||||
{
|
||||
var recordsA = records.ToArray();
|
||||
if (recordsA.Length == 0) return 0;
|
||||
if (!records.Any()) return 0;
|
||||
|
||||
var pocoData = database.PocoDataFactory.ForType(typeof(T));
|
||||
if (pocoData == null) throw new InvalidOperationException("Could not find PocoData for " + typeof(T));
|
||||
|
||||
return BulkInsertRecordsSqlCe(database, pocoData, recordsA);
|
||||
return BulkInsertRecordsSqlCe(database, pocoData, records.ToArray());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,12 +14,12 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
/// <summary>
|
||||
/// Deserialize the data into a <see cref="ContentCacheDataModel"/>
|
||||
/// </summary>
|
||||
ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData);
|
||||
ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData, bool published);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the <see cref="ContentCacheDataModel"/>
|
||||
/// Serializes the <see cref="ContentCacheDataModel"/>
|
||||
/// </summary>
|
||||
ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model);
|
||||
ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model, bool published);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
DateFormatString = "o"
|
||||
};
|
||||
private readonly JsonNameTable _propertyNameTable = new DefaultJsonNameTable();
|
||||
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData)
|
||||
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData, bool published)
|
||||
{
|
||||
if (stringData == null && byteData != null)
|
||||
throw new NotSupportedException($"{typeof(JsonContentNestedDataSerializer)} does not support byte[] serialization");
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
}
|
||||
}
|
||||
|
||||
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model)
|
||||
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model, bool published)
|
||||
{
|
||||
// note that numeric values (which are Int32) are serialized without their
|
||||
// type (eg "value":1234) and JsonConvert by default deserializes them as Int64
|
||||
|
||||
@@ -39,7 +39,8 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
|
||||
_options = defaultOptions
|
||||
.WithResolver(resolver)
|
||||
.WithCompression(MessagePackCompression.Lz4BlockArray);
|
||||
.WithCompression(MessagePackCompression.Lz4BlockArray)
|
||||
.WithSecurity(MessagePackSecurity.UntrustedData);
|
||||
}
|
||||
|
||||
public string ToJson(byte[] bin)
|
||||
@@ -48,12 +49,12 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
return json;
|
||||
}
|
||||
|
||||
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData)
|
||||
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData, bool published)
|
||||
{
|
||||
if (byteData != null)
|
||||
{
|
||||
var cacheModel = MessagePackSerializer.Deserialize<ContentCacheDataModel>(byteData, _options);
|
||||
Expand(content, cacheModel);
|
||||
Expand(content, cacheModel, published);
|
||||
return cacheModel;
|
||||
}
|
||||
else if (stringData != null)
|
||||
@@ -61,7 +62,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
// NOTE: We don't really support strings but it's possible if manually used (i.e. tests)
|
||||
var bin = Convert.FromBase64String(stringData);
|
||||
var cacheModel = MessagePackSerializer.Deserialize<ContentCacheDataModel>(bin, _options);
|
||||
Expand(content, cacheModel);
|
||||
Expand(content, cacheModel, published);
|
||||
return cacheModel;
|
||||
}
|
||||
else
|
||||
@@ -70,9 +71,9 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
}
|
||||
}
|
||||
|
||||
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model)
|
||||
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model, bool published)
|
||||
{
|
||||
Compress(content, model);
|
||||
Compress(content, model, published);
|
||||
var bytes = MessagePackSerializer.Serialize(model, _options);
|
||||
return new ContentCacheDataSerializationResult(null, bytes);
|
||||
}
|
||||
@@ -80,7 +81,9 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
/// <summary>
|
||||
/// Used during serialization to compress properties
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="published"></param>
|
||||
/// <remarks>
|
||||
/// This will essentially 'double compress' property data. The MsgPack data as a whole will already be compressed
|
||||
/// but this will go a step further and double compress property data so that it is stored in the nucache file
|
||||
@@ -88,11 +91,11 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
/// read/decompressed as a string to be displayed on the front-end. This allows for potentially a significant
|
||||
/// memory savings but could also affect performance of first rendering pages while decompression occurs.
|
||||
/// </remarks>
|
||||
private void Compress(IReadOnlyContentBase content, ContentCacheDataModel model)
|
||||
private void Compress(IReadOnlyContentBase content, ContentCacheDataModel model, bool published)
|
||||
{
|
||||
foreach(var propertyAliasToData in model.PropertyData)
|
||||
{
|
||||
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key))
|
||||
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key, published))
|
||||
{
|
||||
foreach(var property in propertyAliasToData.Value.Where(x => x.Value != null && x.Value is string))
|
||||
{
|
||||
@@ -105,12 +108,14 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
/// <summary>
|
||||
/// Used during deserialization to map the property data as lazy or expand the value
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="nestedData"></param>
|
||||
private void Expand(IReadOnlyContentBase content, ContentCacheDataModel nestedData)
|
||||
/// <param name="published"></param>
|
||||
private void Expand(IReadOnlyContentBase content, ContentCacheDataModel nestedData, bool published)
|
||||
{
|
||||
foreach (var propertyAliasToData in nestedData.PropertyData)
|
||||
{
|
||||
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key))
|
||||
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key,published))
|
||||
{
|
||||
foreach (var property in propertyAliasToData.Value.Where(x => x.Value != null))
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
{
|
||||
@@ -14,7 +13,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache.DataSource
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private readonly IPropertyCacheCompressionOptions _compressionOptions;
|
||||
private readonly ConcurrentDictionary<(int, string), bool> _isCompressedCache = new ConcurrentDictionary<(int, string), bool>();
|
||||
private readonly ConcurrentDictionary<(int, string, bool), bool> _isCompressedCache = new ConcurrentDictionary<(int, string, bool), bool>();
|
||||
|
||||
public MsgPackContentNestedDataSerializerFactory(
|
||||
IContentTypeService contentTypeService,
|
||||
|
||||
@@ -68,7 +68,20 @@ namespace Umbraco.Extensions
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
});
|
||||
builder.Services.AddSingleton<IPropertyCacheCompressionOptions, NoopPropertyCacheCompressionOptions>();
|
||||
|
||||
builder.Services.AddSingleton<IPropertyCacheCompressionOptions>(s =>
|
||||
{
|
||||
IOptions<NuCacheSettings> options = s.GetRequiredService<IOptions<NuCacheSettings>>();
|
||||
|
||||
if (options.Value.NuCacheSerializerType == NuCacheSerializerType.MessagePack &&
|
||||
options.Value.UnPublishedContentCompression)
|
||||
{
|
||||
return new UnPublishedContentPropertyCacheCompressionOptions();
|
||||
}
|
||||
|
||||
return new NoopPropertyCacheCompressionOptions();
|
||||
});
|
||||
|
||||
builder.Services.AddSingleton(s => new ContentDataSerializer(new DictionaryOfPropertyDataSerializer()));
|
||||
|
||||
// add the NuCache health check (hidden from type finder)
|
||||
|
||||
@@ -415,7 +415,7 @@ AND cmsContentNu.nodeId IS NULL
|
||||
UrlSegment = content.GetUrlSegment(_shortStringHelper, _urlSegmentProviders)
|
||||
};
|
||||
|
||||
var serialized = serializer.Serialize(ReadOnlyContentBaseAdapter.Create(content), contentCacheData);
|
||||
var serialized = serializer.Serialize(ReadOnlyContentBaseAdapter.Create(content), contentCacheData, published);
|
||||
|
||||
var dto = new ContentNuDto
|
||||
{
|
||||
@@ -817,12 +817,13 @@ AND cmsContentNu.nodeId IS NULL
|
||||
}
|
||||
else
|
||||
{
|
||||
var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw);
|
||||
bool published = false;
|
||||
var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published);
|
||||
|
||||
d = new ContentData
|
||||
{
|
||||
Name = dto.EditName,
|
||||
Published = false,
|
||||
Published = published,
|
||||
TemplateId = dto.EditTemplateId,
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.EditVersionDate,
|
||||
@@ -847,13 +848,14 @@ AND cmsContentNu.nodeId IS NULL
|
||||
}
|
||||
else
|
||||
{
|
||||
var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw);
|
||||
bool published = true;
|
||||
var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw, published);
|
||||
|
||||
p = new ContentData
|
||||
{
|
||||
Name = dto.PubName,
|
||||
UrlSegment = deserializedContent.UrlSegment,
|
||||
Published = true,
|
||||
Published = published,
|
||||
TemplateId = dto.PubTemplateId,
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.PubVersionDate,
|
||||
@@ -883,12 +885,13 @@ AND cmsContentNu.nodeId IS NULL
|
||||
if (dto.EditData == null && dto.EditDataRaw == null)
|
||||
throw new InvalidOperationException("No data for media " + dto.Id);
|
||||
|
||||
var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw);
|
||||
bool published = true;
|
||||
var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published);
|
||||
|
||||
var p = new ContentData
|
||||
{
|
||||
Name = dto.EditName,
|
||||
Published = true,
|
||||
Published = published,
|
||||
TemplateId = -1,
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.EditVersionDate,
|
||||
|
||||
@@ -56,14 +56,14 @@ namespace Umbraco.Tests.PublishedContent
|
||||
|
||||
var content = Mock.Of<IReadOnlyContentBase>(x => x.ContentTypeId == 1);
|
||||
|
||||
var json = jsonSerializer.Serialize(content, cacheModel).StringData;
|
||||
var msgPack = msgPackSerializer.Serialize(content, cacheModel).ByteData;
|
||||
var json = jsonSerializer.Serialize(content, cacheModel, false).StringData;
|
||||
var msgPack = msgPackSerializer.Serialize(content, cacheModel, false).ByteData;
|
||||
|
||||
Console.WriteLine(json);
|
||||
Console.WriteLine(msgPackSerializer.ToJson(msgPack));
|
||||
|
||||
var jsonContent = jsonSerializer.Deserialize(content, json, null);
|
||||
var msgPackContent = msgPackSerializer.Deserialize(content, null, msgPack);
|
||||
var jsonContent = jsonSerializer.Deserialize(content, json, null, false);
|
||||
var msgPackContent = msgPackSerializer.Deserialize(content, null, msgPack, false);
|
||||
|
||||
|
||||
CollectionAssert.AreEqual(jsonContent.CultureData.Keys, msgPackContent.CultureData.Keys);
|
||||
|
||||
@@ -28,12 +28,9 @@ using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Web.BackOffice.ActionResults;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
using Umbraco.Cms.Web.BackOffice.Extensions;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Cms.Web.BackOffice.ModelBinders;
|
||||
using Umbraco.Cms.Web.Common.ActionsResults;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
@@ -478,6 +475,13 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
return result;
|
||||
}
|
||||
|
||||
private ActionResult<IDictionary<Guid, ContentItemDisplay>> GetEmptyByKeysInternal(Guid[] contentTypeKeys, int parentId)
|
||||
{
|
||||
using var scope = _scopeProvider.CreateScope(autoComplete: true);
|
||||
var contentTypes = _contentTypeService.GetAll(contentTypeKeys).ToList();
|
||||
return GetEmpties(contentTypes, parentId).ToDictionary(x => x.ContentTypeKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of empty content items for all document types.
|
||||
/// </summary>
|
||||
@@ -486,9 +490,22 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
[OutgoingEditorModelEvent]
|
||||
public ActionResult<IDictionary<Guid, ContentItemDisplay>> GetEmptyByKeys([FromQuery] Guid[] contentTypeKeys, [FromQuery] int parentId)
|
||||
{
|
||||
using var scope = _scopeProvider.CreateScope(autoComplete: true);
|
||||
var contentTypes = _contentTypeService.GetAll(contentTypeKeys).ToList();
|
||||
return GetEmpties(contentTypes, parentId).ToDictionary(x => x.ContentTypeKey);
|
||||
return GetEmptyByKeysInternal(contentTypeKeys, parentId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of empty content items for all document types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a post request in order to support a large amount of GUIDs without hitting the URL length limit.
|
||||
/// </remarks>
|
||||
/// <param name="contentTypeByKeys"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[OutgoingEditorModelEvent]
|
||||
public ActionResult<IDictionary<Guid, ContentItemDisplay>> GetEmptyByKeys(ContentTypesByKeys contentTypeByKeys)
|
||||
{
|
||||
return GetEmptyByKeysInternal(contentTypeByKeys.ContentTypeKeys, contentTypeByKeys.ParentId);
|
||||
}
|
||||
|
||||
[OutgoingEditorModelEvent]
|
||||
|
||||
@@ -21,7 +21,6 @@ using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Cms.Web.Common.Controllers;
|
||||
using Umbraco.Cms.Web.Common.Filters;
|
||||
using Umbraco.Core.Dashboards;
|
||||
using Umbraco.Extensions;
|
||||
using Constants = Umbraco.Cms.Core.Constants;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@ using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
|
||||
@@ -217,9 +217,11 @@ namespace Umbraco.Extensions
|
||||
}
|
||||
|
||||
var url = mediaItem.GetCropUrl(cropAlias: cropAlias, useCropDimensions: true);
|
||||
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
return CreateHtmlString(url, htmlEncode);
|
||||
}
|
||||
|
||||
private static IHtmlContent CreateHtmlString(string url, bool htmlEncode) => htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
|
||||
public static IHtmlContent GetCropUrl(this IUrlHelper urlHelper, IPublishedContent mediaItem, string propertyAlias, string cropAlias, bool htmlEncode = true)
|
||||
{
|
||||
if (mediaItem == null)
|
||||
@@ -228,7 +230,7 @@ namespace Umbraco.Extensions
|
||||
}
|
||||
|
||||
var url = mediaItem.GetCropUrl(propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true);
|
||||
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
return CreateHtmlString(url, htmlEncode);
|
||||
}
|
||||
|
||||
public static IHtmlContent GetCropUrl(this IUrlHelper urlHelper,
|
||||
@@ -256,7 +258,7 @@ namespace Umbraco.Extensions
|
||||
var url = mediaItem.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode,
|
||||
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode,
|
||||
upScale);
|
||||
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
return CreateHtmlString(url, htmlEncode);
|
||||
}
|
||||
|
||||
public static IHtmlContent GetCropUrl(this IUrlHelper urlHelper,
|
||||
@@ -281,7 +283,7 @@ namespace Umbraco.Extensions
|
||||
var url = imageUrl.GetCropUrl(imageCropperValue, width, height, cropAlias, quality, imageCropMode,
|
||||
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode,
|
||||
upScale);
|
||||
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
|
||||
return CreateHtmlString(url, htmlEncode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
630
src/Umbraco.Web.UI.Client/package-lock.json
generated
630
src/Umbraco.Web.UI.Client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -126,7 +126,9 @@
|
||||
// close all editors
|
||||
if (args && !args.editor && args.editors.length === 0) {
|
||||
editorCount = 0;
|
||||
scope.editors = [];
|
||||
scope.editors = [];
|
||||
// Remove the inert attribute from the #mainwrapper
|
||||
focusLockService.removeInertAttribute();
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbImageCrop',
|
||||
function ($timeout, $window, cropperHelper) {
|
||||
function ($timeout, cropperHelper, windowResizeListener) {
|
||||
|
||||
const MAX_SCALE = 4;
|
||||
|
||||
@@ -26,7 +26,7 @@ angular.module("umbraco.directives")
|
||||
forceUpdate: '@?'
|
||||
},
|
||||
|
||||
link: function (scope, element, attrs, windowResizeListener) {
|
||||
link: function (scope, element, attrs) {
|
||||
|
||||
var unsubscribe = [];
|
||||
let sliderRef = null;
|
||||
@@ -72,7 +72,7 @@ angular.module("umbraco.directives")
|
||||
};
|
||||
|
||||
function updateSlider() {
|
||||
if(sliderRef) {
|
||||
if (sliderRef) {
|
||||
// Update slider range min/max
|
||||
sliderRef.noUiSlider.updateOptions({
|
||||
"range": {
|
||||
@@ -102,7 +102,7 @@ angular.module("umbraco.directives")
|
||||
// cross-browser wheel delta
|
||||
var delta = Math.max(-50, Math.min(50, (event.wheelDelta || -event.detail)));
|
||||
|
||||
if(sliderRef) {
|
||||
if (sliderRef) {
|
||||
var currentScale =sliderRef.noUiSlider.get();
|
||||
|
||||
var newScale = Math.min(Math.max(currentScale + delta*.001*scope.dimensions.image.ratio, scope.dimensions.scale.min), scope.dimensions.scale.max);
|
||||
@@ -127,8 +127,8 @@ angular.module("umbraco.directives")
|
||||
'left': (parseInt(scope.dimensions.margin.left, 10)) + 'px'
|
||||
}
|
||||
};
|
||||
updateStyles();
|
||||
|
||||
updateStyles();
|
||||
|
||||
//elements
|
||||
var $viewport = element.find(".viewport");
|
||||
@@ -138,11 +138,11 @@ angular.module("umbraco.directives")
|
||||
$overlay.bind("focus", function () {
|
||||
$overlay.bind("DOMMouseScroll mousewheel onmousewheel", onScroll);
|
||||
});
|
||||
|
||||
$overlay.bind("blur", function () {
|
||||
$overlay.unbind("DOMMouseScroll mousewheel onmousewheel", onScroll);
|
||||
});
|
||||
|
||||
|
||||
//default constraints for drag n drop
|
||||
var constraints = { left: { max: 0, min: 0 }, top: { max: 0, min: 0 } };
|
||||
scope.constraints = constraints;
|
||||
|
||||
@@ -57,7 +57,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* Do stuff...
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
@@ -691,11 +691,12 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
getScaffoldByKeys: function (parentId, scaffoldKeys) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetEmptyByKeys",
|
||||
{ contentTypeKeys: scaffoldKeys, parentId: parentId })),
|
||||
"GetEmptyByKeys"),
|
||||
{ contentTypeKeys: scaffoldKeys, parentId: parentId }
|
||||
),
|
||||
'Failed to retrieve data for empty content items ids' + scaffoldKeys.join(", "))
|
||||
.then(function (result) {
|
||||
Object.keys(result).map(function(key) {
|
||||
@@ -804,7 +805,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
|
||||
//converts the value to a js bool
|
||||
function toBool(v) {
|
||||
if (Utilities.isNumber(v)) {
|
||||
|
||||
@@ -487,7 +487,7 @@
|
||||
* @returns {Object | null} Scaffold model for the that content type. Or null if the scaffolding model dosnt exist in this context.
|
||||
*/
|
||||
getScaffoldFromKey: function (contentTypeKey) {
|
||||
return this.scaffolds.find(o => o.contentTypeKey === contentTypeKey);
|
||||
return this.scaffolds.find(o => o.contentTypeKey === contentTypeKey) || null;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -499,7 +499,7 @@
|
||||
* @returns {Object | null} Scaffold model for the that content type. Or null if the scaffolding model dosnt exist in this context.
|
||||
*/
|
||||
getScaffoldFromAlias: function (contentTypeAlias) {
|
||||
return this.scaffolds.find(o => o.contentTypeAlias === contentTypeAlias);
|
||||
return this.scaffolds.find(o => o.contentTypeAlias === contentTypeAlias) || null;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -609,10 +609,14 @@
|
||||
blockObject.settingsData = settingsData;
|
||||
|
||||
// make basics from scaffold
|
||||
blockObject.settings = Utilities.copy(settingsScaffold);
|
||||
ensureUdiAndKey(blockObject.settings, settingsUdi);
|
||||
if (settingsScaffold !== null) {// We might not have settingsScaffold
|
||||
blockObject.settings = Utilities.copy(settingsScaffold);
|
||||
ensureUdiAndKey(blockObject.settings, settingsUdi);
|
||||
|
||||
mapToElementModel(blockObject.settings, settingsData);
|
||||
mapToElementModel(blockObject.settings, settingsData);
|
||||
} else {
|
||||
blockObject.settings = null;
|
||||
}
|
||||
|
||||
// add settings content-app
|
||||
appendSettingsContentApp(blockObject.content, this.__labels.settingsName);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
angular.module('umbraco.services')
|
||||
.factory('localizationService', function ($http, $q, eventsService, $window, $filter, userService) {
|
||||
.factory('localizationService', function ($http, $q, eventsService) {
|
||||
|
||||
// TODO: This should be injected as server vars
|
||||
var url = "LocalizedText";
|
||||
@@ -61,14 +61,14 @@ angular.module('umbraco.services')
|
||||
|
||||
return "[" + alias + "]";
|
||||
}
|
||||
|
||||
|
||||
var service = {
|
||||
|
||||
|
||||
|
||||
// loads the language resource file from the server
|
||||
initLocalizedResources: function () {
|
||||
|
||||
// TODO: This promise handling is super ugly, we should just be returnning the promise from $http and returning inner values.
|
||||
// TODO: This promise handling is super ugly, we should just be returnning the promise from $http and returning inner values.
|
||||
|
||||
var deferred = $q.defer();
|
||||
|
||||
@@ -120,7 +120,7 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Helper to tokenize and compile a localization string
|
||||
* @param {String} value the value to tokenize
|
||||
* @param {Object} scope the $scope object
|
||||
* @param {Object} scope the $scope object
|
||||
* @returns {String} tokenized resource string
|
||||
*/
|
||||
tokenize: function (value, scope) {
|
||||
@@ -138,8 +138,8 @@ angular.module('umbraco.services')
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.localizationService#tokenReplace
|
||||
@@ -148,19 +148,19 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Helper to replace tokens
|
||||
* @param {String} value the text-string to manipulate
|
||||
* @param {Array} tekens An array of tokens values
|
||||
* @param {Array} tekens An array of tokens values
|
||||
* @returns {String} Replaced test-string
|
||||
*/
|
||||
tokenReplace: function (text, tokens) {
|
||||
if (tokens) {
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
text = text.replace("%" + i + "%", tokens[i]);
|
||||
text = text.replace("%" + i + "%", _.escape(tokens[i]));
|
||||
}
|
||||
}
|
||||
return text;
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.localizationService#localize
|
||||
@@ -168,16 +168,16 @@ angular.module('umbraco.services')
|
||||
*
|
||||
* @description
|
||||
* Checks the dictionary for a localized resource string
|
||||
* @param {String} value the area/key to localize in the format of 'section_key'
|
||||
* @param {String} value the area/key to localize in the format of 'section_key'
|
||||
* alternatively if no section is set such as 'key' then we assume the key is to be looked in
|
||||
* the 'general' section
|
||||
*
|
||||
*
|
||||
* @param {Array} tokens if specified this array will be sent as parameter values
|
||||
* This replaces %0% and %1% etc in the dictionary key value with the passed in strings
|
||||
*
|
||||
* @param {String} fallbackValue if specified this string will be returned if no matching
|
||||
*
|
||||
* @param {String} fallbackValue if specified this string will be returned if no matching
|
||||
* entry was found in the dictionary
|
||||
*
|
||||
*
|
||||
* @returns {String} localized resource string
|
||||
*/
|
||||
localize: function (value, tokens, fallbackValue) {
|
||||
@@ -194,7 +194,7 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Checks the dictionary for multipe localized resource strings at once, preventing the need for nested promises
|
||||
* with localizationService.localize
|
||||
*
|
||||
*
|
||||
* ##Usage
|
||||
* <pre>
|
||||
* localizationService.localizeMany(["speechBubbles_templateErrorHeader", "speechBubbles_templateErrorText"]).then(function(data){
|
||||
@@ -203,11 +203,11 @@ angular.module('umbraco.services')
|
||||
* notificationService.error(header, message);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
* alternatively if no section is set such as 'key' then we assume the key is to be looked in
|
||||
* the 'general' section
|
||||
*
|
||||
*
|
||||
* @returns {Array} An array of localized resource string in the same order
|
||||
*/
|
||||
localizeMany: function(keys) {
|
||||
@@ -234,18 +234,18 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Checks the dictionary for multipe localized resource strings at once & concats them to a single string
|
||||
* Which was not possible with localizationSerivce.localize() due to returning a promise
|
||||
*
|
||||
*
|
||||
* ##Usage
|
||||
* <pre>
|
||||
* localizationService.concat(["speechBubbles_templateErrorHeader", "speechBubbles_templateErrorText"]).then(function(data){
|
||||
* var combinedText = data;
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
* alternatively if no section is set such as 'key' then we assume the key is to be looked in
|
||||
* the 'general' section
|
||||
*
|
||||
*
|
||||
* @returns {String} An concatenated string of localized resource string passed into the function in the same order
|
||||
*/
|
||||
concat: function(keys) {
|
||||
@@ -280,7 +280,7 @@ angular.module('umbraco.services')
|
||||
* @description
|
||||
* Checks the dictionary for multipe localized resource strings at once & formats a tokenized message
|
||||
* Which was not possible with localizationSerivce.localize() due to returning a promise
|
||||
*
|
||||
*
|
||||
* ##Usage
|
||||
* <pre>
|
||||
* localizationService.format(["template_insert", "template_insertSections"], "%0% %1%").then(function(data){
|
||||
@@ -288,14 +288,14 @@ angular.module('umbraco.services')
|
||||
* var formattedResult = data;
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
*
|
||||
* @param {Array} keys is an array of strings of the area/key to localize in the format of 'section_key'
|
||||
* alternatively if no section is set such as 'key' then we assume the key is to be looked in
|
||||
* the 'general' section
|
||||
*
|
||||
*
|
||||
* @param {String} message is the string you wish to replace containing tokens in the format of %0% and %1%
|
||||
* with the localized resource strings
|
||||
*
|
||||
*
|
||||
* @returns {String} An concatenated string of localized resource string passed into the function in the same order
|
||||
*/
|
||||
format: function(keys, message){
|
||||
@@ -330,7 +330,7 @@ angular.module('umbraco.services')
|
||||
resourceFileLoadStatus = "none";
|
||||
resourceLoadingPromise = [];
|
||||
});
|
||||
|
||||
|
||||
|
||||
// return the local instance when called
|
||||
return service;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
function windowResizeListener($rootScope) {
|
||||
|
||||
var WinReszier = (function () {
|
||||
var WinResizer = (function () {
|
||||
var registered = [];
|
||||
var inited = false;
|
||||
var resize = _.debounce(function(ev) {
|
||||
@@ -51,7 +51,7 @@ function windowResizeListener($rootScope) {
|
||||
* @param {Function} cb
|
||||
*/
|
||||
register: function (cb) {
|
||||
WinReszier.register(cb);
|
||||
WinResizer.register(cb);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -59,9 +59,9 @@ function windowResizeListener($rootScope) {
|
||||
* @param {Function} cb
|
||||
*/
|
||||
unregister: function(cb) {
|
||||
WinReszier.unregister(cb);
|
||||
WinResizer.unregister(cb);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.services').factory('windowResizeListener', windowResizeListener);
|
||||
angular.module('umbraco.services').factory('windowResizeListener', windowResizeListener);
|
||||
|
||||
@@ -154,9 +154,10 @@
|
||||
currentForm.$dirty = false;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.dialog.confirmDiscardChanges = false;
|
||||
vm.saveState = "success";
|
||||
vm.saveSuccces = true;
|
||||
|
||||
}, function(error){
|
||||
vm.saveState = "error";
|
||||
vm.saveError = error;
|
||||
|
||||
@@ -98,6 +98,10 @@
|
||||
|
||||
vm.model.value.forEach(mediaEntry => updateMediaEntryData(mediaEntry));
|
||||
|
||||
// set the onValueChanged callback, this will tell us if the media picker model changed on the server
|
||||
// once the data is submitted. If so we need to re-initialize
|
||||
vm.model.onValueChanged = onServerValueChanged;
|
||||
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
|
||||
if (!vm.model.config.startNodeId) {
|
||||
@@ -120,6 +124,15 @@
|
||||
|
||||
};
|
||||
|
||||
function onServerValueChanged(newVal, oldVal) {
|
||||
if(newVal === null || !Array.isArray(newVal)) {
|
||||
newVal = [];
|
||||
vm.model.value = newVal;
|
||||
}
|
||||
|
||||
vm.model.value.forEach(mediaEntry => updateMediaEntryData(mediaEntry));
|
||||
}
|
||||
|
||||
function setDirty() {
|
||||
if (vm.propertyForm) {
|
||||
vm.propertyForm.$setDirty();
|
||||
@@ -259,7 +272,7 @@
|
||||
function setActiveMedia(mediaEntryOrNull) {
|
||||
vm.activeMediaEntry = mediaEntryOrNull;
|
||||
}
|
||||
|
||||
|
||||
function editMedia(mediaEntry, options, $event) {
|
||||
|
||||
if($event)
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<RazorCompileOnBuild>false</RazorCompileOnBuild>
|
||||
<RazorCompileOnPublish>false</RazorCompileOnPublish>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<PropertyGroup>
|
||||
<BellePath>$(ProjectDir)wwwroot/umbraco</BellePath>
|
||||
<JsonSchemaPath>$(ProjectDir)umbraco/config/appsettings-schema.json</JsonSchemaPath>
|
||||
@@ -107,7 +107,7 @@
|
||||
<Target Name="JsonSchemaBuild">
|
||||
<!-- <Exec WorkingDirectory="$(ProjectDir)/../../" Command="powershell -ExecutionPolicy RemoteSigned -Command '&dotnet run --project $pwd/src/JsonSchema/JsonSchema.csproj -c Release -- --outputFile $pwd/src/Umbraco.Web.UI.NetCore/$(JsonSchemaPath)'" />-->
|
||||
</Target>
|
||||
|
||||
|
||||
<!-- clean Belle when cleaning and rebuilding, but only in Visual Studio -->
|
||||
<Target Name="CleanPreconditions" AfterTargets="Clean" Condition="'$(UmbracoBuild)' == ''">
|
||||
<Message Text="-CleanPreconditions-" Importance="high" />
|
||||
|
||||
Reference in New Issue
Block a user