Add Multi Url Picker
This commit is contained in:
committed by
Sebastiaan Janssen
parent
9b9c9ef455
commit
e1175b814e
@@ -178,6 +178,11 @@ namespace Umbraco.Core
|
||||
/// Nested Content.
|
||||
/// </summary>
|
||||
public const string NestedContent = "Umbraco.NestedContent";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the multi url picker editor.
|
||||
/// </summary>
|
||||
public const string MultiUrlPicker = "Umbraco.MultiUrlPicker";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
function multiUrlPickerController($scope, angularHelper, localizationService, entityResource, iconHelper, editorService) {
|
||||
|
||||
$scope.renderModel = [];
|
||||
|
||||
if ($scope.preview) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Array.isArray($scope.model.value)) {
|
||||
$scope.model.value = [];
|
||||
}
|
||||
|
||||
var currentForm = angularHelper.getCurrentForm($scope);
|
||||
|
||||
$scope.sortableOptions = {
|
||||
distance: 10,
|
||||
tolerance: "pointer",
|
||||
scroll: true,
|
||||
zIndex: 6000,
|
||||
update: function () {
|
||||
currentForm.$setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.model.value.forEach(function (link) {
|
||||
link.icon = iconHelper.convertFromLegacyIcon(link.icon);
|
||||
$scope.renderModel.push(link);
|
||||
});
|
||||
|
||||
$scope.$on("formSubmitting", function () {
|
||||
$scope.model.value = $scope.renderModel;
|
||||
});
|
||||
|
||||
$scope.$watch(
|
||||
function () {
|
||||
return $scope.renderModel.length;
|
||||
},
|
||||
function () {
|
||||
//Validate!
|
||||
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
|
||||
$scope.multiUrlPickerForm.minCount.$setValidity("minCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.multiUrlPickerForm.minCount.$setValidity("minCount", true);
|
||||
}
|
||||
|
||||
if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
|
||||
$scope.multiUrlPickerForm.maxCount.$setValidity("maxCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.multiUrlPickerForm.maxCount.$setValidity("maxCount", true);
|
||||
}
|
||||
$scope.sortableOptions.disabled = $scope.renderModel.length === 1;
|
||||
}
|
||||
);
|
||||
|
||||
$scope.remove = function ($index) {
|
||||
$scope.renderModel.splice($index, 1);
|
||||
|
||||
currentForm.$setDirty();
|
||||
};
|
||||
|
||||
$scope.openLinkPicker = function (link, $index) {
|
||||
var target = link ? {
|
||||
name: link.name,
|
||||
anchor: link.queryString,
|
||||
// the linkPicker breaks if it get an udi for media
|
||||
udi: link.isMedia ? null : link.udi,
|
||||
url: link.url,
|
||||
target: link.target
|
||||
} : null;
|
||||
|
||||
var linkPicker = {
|
||||
currentTarget: target,
|
||||
submit: function (model) {
|
||||
if (model.target.url) {
|
||||
// if an anchor exists, check that it is appropriately prefixed
|
||||
if (model.target.anchor && model.target.anchor[0] !== '?' && model.target.anchor[0] !== '#') {
|
||||
model.target.anchor = (model.target.anchor.indexOf('=') === -1 ? '#' : '?') + model.target.anchor;
|
||||
}
|
||||
if (link) {
|
||||
if (link.isMedia && link.url === model.target.url) {
|
||||
// we can assume the existing media item is changed and no new file has been selected
|
||||
// so we don't need to update the udi and isMedia fields
|
||||
} else {
|
||||
link.udi = model.target.udi;
|
||||
link.isMedia = model.target.isMedia;
|
||||
}
|
||||
|
||||
link.name = model.target.name || model.target.url;
|
||||
link.queryString = model.target.anchor;
|
||||
link.target = model.target.target;
|
||||
link.url = model.target.url;
|
||||
} else {
|
||||
link = {
|
||||
isMedia: model.target.isMedia,
|
||||
name: model.target.name || model.target.url,
|
||||
queryString: model.target.anchor,
|
||||
target: model.target.target,
|
||||
udi: model.target.udi,
|
||||
url: model.target.url
|
||||
};
|
||||
$scope.renderModel.push(link);
|
||||
}
|
||||
|
||||
if (link.udi) {
|
||||
var entityType = link.isMedia ? "media" : "document";
|
||||
|
||||
entityResource.getById(link.udi, entityType).then(function (data) {
|
||||
link.icon = iconHelper.convertFromLegacyIcon(data.icon);
|
||||
link.published = (data.metaData && data.metaData.IsPublished === false && entityType === "Document") ? false : true;
|
||||
link.trashed = data.trashed;
|
||||
if (link.trashed) {
|
||||
item.url = localizationService.dictionary.general_recycleBin;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
link.icon = "icon-link";
|
||||
link.published = true;
|
||||
}
|
||||
|
||||
currentForm.$setDirty();
|
||||
}
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
editorService.linkPicker(linkPicker);
|
||||
};
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.MultiUrlPickerController", multiUrlPickerController);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.MultiUrlPickerController" class="umb-property-editor umb-contentpicker">
|
||||
<p ng-if="(renderModel|filter:{trashed:true}).length == 1"><localize key="contentPicker_pickedTrashedItem"></localize></p>
|
||||
<p ng-if="(renderModel|filter:{trashed:true}).length > 1"><localize key="contentPicker_pickedTrashedItems"></localize></p>
|
||||
|
||||
<ng-form name="multiUrlPickerForm">
|
||||
<div ui-sortable="sortableOptions" ng-model="renderModel">
|
||||
<umb-node-preview ng-repeat="link in renderModel"
|
||||
icon="link.icon"
|
||||
name="link.name"
|
||||
published="link.published"
|
||||
description="link.url + (link.queryString ? link.queryString : '')"
|
||||
sortable="!sortableOptions.disabled"
|
||||
allow-remove="true"
|
||||
allow-edit="true"
|
||||
on-remove="remove($index)"
|
||||
on-edit="openContentEditor(link, $index)">
|
||||
</umb-node-preview>
|
||||
</div>
|
||||
|
||||
<a ng-show="!model.config.maxNumber || renderModel.length < model.config.maxNumber"
|
||||
class="umb-node-preview-add"
|
||||
href
|
||||
ng-click="openLinkPicker()"
|
||||
prevent-default>
|
||||
<localize key="general_add">Add</localize>
|
||||
</a>
|
||||
|
||||
<div class="umb-contentpicker__min-max-help">
|
||||
|
||||
|
||||
<!-- Both min and max items -->
|
||||
<span ng-if="model.config.minNumber && model.config.maxNumber && model.config.minNumber !== model.config.maxNumber">
|
||||
<span ng-if="renderModel.length < model.config.maxNumber">Add between {{model.config.minNumber}} and {{model.config.maxNumber}} items</span>
|
||||
<span ng-if="renderModel.length > model.config.maxNumber">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected"> items selected</localize>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<!-- Equal min and max -->
|
||||
<span ng-if="model.config.minNumber && model.config.maxNumber && model.config.minNumber === model.config.maxNumber">
|
||||
<span ng-if="renderModel.length < model.config.maxNumber">Add {{model.config.minNumber - renderModel.length}} item(s)</span>
|
||||
<span ng-if="renderModel.length > model.config.maxNumber">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected"> items selected</localize>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<!-- Only max -->
|
||||
<span ng-if="!model.config.minNumber && model.config.maxNumber">
|
||||
<span ng-if="renderModel.length < model.config.maxNumber">Add up to {{model.config.maxNumber}} items</span>
|
||||
<span ng-if="renderModel.length > model.config.maxNumber">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected">items selected</localize>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<!-- Only min -->
|
||||
<span ng-if="model.config.minNumber && !model.config.maxNumber && renderModel.length < model.config.minNumber">
|
||||
Add at least {{model.config.minNumber}} item(s)
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<!--These are here because we need ng-form fields to validate against-->
|
||||
<input type="hidden" name="minCount" ng-model="renderModel" />
|
||||
<input type="hidden" name="maxCount" ng-model="renderModel" />
|
||||
|
||||
<div ng-messages="contentPickerForm.minCount.$error" show-validation-on-submit>
|
||||
<div class="help-inline" ng-message="minCount">
|
||||
<localize key="validation_minCount">You need to add at least</localize> {{model.config.minNumber}} <localize key="validation_items">items</localize>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-messages="contentPickerForm.maxCount.$error" show-validation-on-submit>
|
||||
<div class="help-inline" ng-message="maxCount">
|
||||
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected">items selected</localize>
|
||||
</div>
|
||||
</div>
|
||||
</ng-form>
|
||||
</div>
|
||||
36
src/Umbraco.Web/Models/ContentEditing/LinkDisplay.cs
Normal file
36
src/Umbraco.Web/Models/ContentEditing/LinkDisplay.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
[DataContract(Name = "link", Namespace = "")]
|
||||
internal class LinkDisplay
|
||||
{
|
||||
[DataMember(Name = "icon")]
|
||||
public string Icon { get; set; }
|
||||
|
||||
[DataMember(Name = "isMedia")]
|
||||
public bool IsMedia { get; set; }
|
||||
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "published")]
|
||||
public bool Published { get; set; }
|
||||
|
||||
[DataMember(Name = "queryString")]
|
||||
public string QueryString { get; set; }
|
||||
|
||||
[DataMember(Name = "target")]
|
||||
public string Target { get; set; }
|
||||
|
||||
[DataMember(Name = "trashed")]
|
||||
public bool Trashed { get; set; }
|
||||
|
||||
[DataMember(Name = "udi")]
|
||||
public GuidUdi Udi { get; set; }
|
||||
|
||||
[DataMember(Name = "url")]
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
||||
13
src/Umbraco.Web/Models/Link.cs
Normal file
13
src/Umbraco.Web/Models/Link.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public class Link
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Target { get; set; }
|
||||
public LinkType Type { get; set; }
|
||||
public Udi Udi { get; set; }
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
||||
9
src/Umbraco.Web/Models/LinkType.cs
Normal file
9
src/Umbraco.Web/Models/LinkType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public enum LinkType
|
||||
{
|
||||
Content,
|
||||
Media,
|
||||
External
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
public class MultiUrlPickerConfiguration
|
||||
{
|
||||
[ConfigurationField("minNumber", "Minimum number of items", "number")]
|
||||
public int MinNumber { get; set; }
|
||||
|
||||
[ConfigurationField("maxNumber", "Maximum number of items", "number")]
|
||||
public int MaxNumber { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
public class MultiUrlPickerConfigurationEditor : ConfigurationEditor<MultiUrlPickerConfiguration>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MultiUrlPicker, EditorType.PropertyValue|EditorType.MacroParameter, "Multi Url Picker", "multiurlpicker", ValueType = "JSON", Group = "pickers", Icon = "icon-link")]
|
||||
public class MultiUrlPickerPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
|
||||
|
||||
public MultiUrlPickerPropertyEditor(ILogger logger, IEntityService entityService, IPublishedSnapshotAccessor publishedSnapshotAccessor) : base(logger, EditorType.PropertyValue|EditorType.MacroParameter)
|
||||
{
|
||||
_entityService = entityService ?? throw new ArgumentNullException(nameof(entityService));
|
||||
_publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor));
|
||||
}
|
||||
|
||||
protected override IConfigurationEditor CreateConfigurationEditor() => new MultiUrlPickerConfigurationEditor();
|
||||
|
||||
protected override IDataValueEditor CreateValueEditor() => new MultiUrlPickerValueEditor(_entityService, _publishedSnapshotAccessor, Logger, Attribute);
|
||||
}
|
||||
}
|
||||
176
src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs
Normal file
176
src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
public class MultiUrlPickerValueEditor : DataValueEditor
|
||||
{
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
|
||||
|
||||
public MultiUrlPickerValueEditor(IEntityService entityService, IPublishedSnapshotAccessor publishedSnapshotAccessor, ILogger logger, DataEditorAttribute attribute) : base(attribute)
|
||||
{
|
||||
_entityService = entityService ?? throw new ArgumentNullException(nameof(entityService));
|
||||
_publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null)
|
||||
{
|
||||
var value = property.GetValue(culture, segment)?.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return Enumerable.Empty<object>();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var links = JsonConvert.DeserializeObject<List<MultiUrlPickerValueEditor.LinkDto>>(value);
|
||||
|
||||
var documentLinks = links.FindAll(link => link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Document);
|
||||
var mediaLinks = links.FindAll(link => link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Media);
|
||||
|
||||
var entities = new List<IEntitySlim>();
|
||||
if (documentLinks.Count > 0)
|
||||
{
|
||||
entities.AddRange(
|
||||
_entityService.GetAll(UmbracoObjectTypes.Document, documentLinks.Select(link => link.Udi.Guid).ToArray())
|
||||
);
|
||||
}
|
||||
|
||||
if (mediaLinks.Count > 0)
|
||||
{
|
||||
entities.AddRange(
|
||||
_entityService.GetAll(UmbracoObjectTypes.Media, mediaLinks.Select(link => link.Udi.Guid).ToArray())
|
||||
);
|
||||
}
|
||||
|
||||
var result = new List<LinkDisplay>();
|
||||
foreach (var dto in links)
|
||||
{
|
||||
GuidUdi udi = null;
|
||||
var icon = "icon-link";
|
||||
var isMedia = false;
|
||||
var published = true;
|
||||
var trashed = false;
|
||||
var url = dto.Url;
|
||||
|
||||
if (dto.Udi != null)
|
||||
{
|
||||
IUmbracoEntity entity = entities.Find(e => e.Key == dto.Udi.Guid);
|
||||
if (entity == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entity is IDocumentEntitySlim documentEntity)
|
||||
{
|
||||
icon = documentEntity.ContentTypeIcon;
|
||||
published = culture == null ? documentEntity.Published : documentEntity.PublishedCultures.Contains(culture);
|
||||
udi = new GuidUdi(Constants.UdiEntityType.Document, documentEntity.Key);
|
||||
url = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(entity.Key)?.Url ?? "#";
|
||||
trashed = documentEntity.Trashed;
|
||||
}
|
||||
else if(entity is IContentEntitySlim contentEntity)
|
||||
{
|
||||
icon = contentEntity.ContentTypeIcon;
|
||||
isMedia = true;
|
||||
published = !contentEntity.Trashed;
|
||||
udi = new GuidUdi(Constants.UdiEntityType.Media, contentEntity.Key);
|
||||
url = _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(entity.Key)?.Url ?? "#";
|
||||
trashed = contentEntity.Trashed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not supported
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(new LinkDisplay
|
||||
{
|
||||
Icon = icon,
|
||||
IsMedia = isMedia,
|
||||
Name = dto.Name,
|
||||
Target = dto.Target,
|
||||
Trashed = trashed,
|
||||
Published = published,
|
||||
Udi = udi,
|
||||
Url = url
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error<MultiUrlPickerValueEditor>("Error getting links", ex);
|
||||
}
|
||||
|
||||
return base.ToEditor(property, dataTypeService, culture, segment);
|
||||
}
|
||||
|
||||
|
||||
public override object FromEditor(ContentPropertyData editorValue, object currentValue)
|
||||
{
|
||||
var value = editorValue.Value?.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return JsonConvert.SerializeObject(
|
||||
from link in JsonConvert.DeserializeObject<List<LinkDisplay>>(value)
|
||||
select new MultiUrlPickerValueEditor.LinkDto
|
||||
{
|
||||
Name = link.Name,
|
||||
Target = link.Target,
|
||||
Udi = link.Udi,
|
||||
Url = link.Udi == null ? link.Url : null, // only save the url for external links
|
||||
},
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error<MultiUrlPickerValueEditor>("Error saving links", ex);
|
||||
}
|
||||
|
||||
return base.FromEditor(editorValue, currentValue);
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
internal class LinkDto
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "target")]
|
||||
public string Target { get; set; }
|
||||
|
||||
[DataMember(Name = "udi")]
|
||||
public GuidUdi Udi { get; set; }
|
||||
|
||||
[DataMember(Name = "url")]
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
{
|
||||
public class MultiUrlPickerValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
|
||||
private readonly IProfilingLogger _proflog;
|
||||
|
||||
public MultiUrlPickerValueConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor, IProfilingLogger proflog)
|
||||
{
|
||||
_publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor));
|
||||
_proflog = proflog ?? throw new ArgumentNullException(nameof(proflog));
|
||||
}
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType) => Constants.PropertyEditors.Aliases.MultiUrlPicker.Equals(propertyType.EditorAlias);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType) =>
|
||||
propertyType.DataType.ConfigurationAs<MultiUrlPickerConfiguration>().MaxNumber == 1 ?
|
||||
typeof(Link) :
|
||||
typeof(IEnumerable<Link>);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) => PropertyCacheLevel.Snapshot;
|
||||
|
||||
public override bool? IsValue(object value, PropertyValueLevel level) => value?.ToString() != "[]";
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview) => source?.ToString();
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
using (_proflog.DebugDuration<MultiUrlPickerValueConverter>($"ConvertPropertyToLinks ({propertyType.DataType.Id})"))
|
||||
{
|
||||
var maxNumber = propertyType.DataType.ConfigurationAs<MultiUrlPickerConfiguration>().MaxNumber;
|
||||
|
||||
if (inter == null)
|
||||
{
|
||||
return maxNumber == 1 ? null : Enumerable.Empty<Link>();
|
||||
}
|
||||
|
||||
var links = new List<Link>();
|
||||
var dtos = JsonConvert.DeserializeObject<IEnumerable<MultiUrlPickerValueEditor.LinkDto>>(inter.ToString());
|
||||
|
||||
foreach (var dto in dtos)
|
||||
{
|
||||
var type = LinkType.External;
|
||||
var url = dto.Url;
|
||||
|
||||
if (dto.Udi != null)
|
||||
{
|
||||
type = dto.Udi.EntityType == Core.Constants.UdiEntityType.Media
|
||||
? LinkType.Media
|
||||
: LinkType.Content;
|
||||
|
||||
var content = type == LinkType.Media ?
|
||||
_publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(preview, dto.Udi.Guid) :
|
||||
_publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(preview, dto.Udi.Guid);
|
||||
|
||||
if (content == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
url = content.Url;
|
||||
}
|
||||
|
||||
links.Add(
|
||||
new Link
|
||||
{
|
||||
Name = dto.Name,
|
||||
Target = dto.Target,
|
||||
Type = type,
|
||||
Udi = dto.Udi,
|
||||
Url = url,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (maxNumber == 1) return links.FirstOrDefault();
|
||||
if (maxNumber > 0) return links.Take(maxNumber);
|
||||
return links;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,8 +167,16 @@
|
||||
<Compile Include="Media\TypeDetector\SvgDetector.cs" />
|
||||
<Compile Include="Media\TypeDetector\TIFFDetector.cs" />
|
||||
<Compile Include="Media\UploadAutoFillProperties.cs" />
|
||||
<Compile Include="Models\ContentEditing\LinkDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroParameterDisplay.cs" />
|
||||
<Compile Include="Models\Link.cs" />
|
||||
<Compile Include="Models\LinkType.cs" />
|
||||
<Compile Include="PropertyEditors\MultiUrlPickerConfiguration.cs" />
|
||||
<Compile Include="PropertyEditors\MultiUrlPickerConfigurationEditor.cs" />
|
||||
<Compile Include="PropertyEditors\MultiUrlPickerPropertyEditor.cs" />
|
||||
<Compile Include="PropertyEditors\MultiUrlPickerValueEditor.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MultiUrlPickerValueConverter.cs" />
|
||||
<Compile Include="Trees\BackOfficeSectionCollectionBuilder.cs" />
|
||||
<Compile Include="Trees\MediaBackOfficeSection.cs" />
|
||||
<Compile Include="Trees\MembersBackOfficeSection.cs" />
|
||||
|
||||
Reference in New Issue
Block a user