Merge remote-tracking branch 'origin/temp8' into temp8-dashboards-collection

This commit is contained in:
Bjarke Berg
2019-01-24 13:27:15 +01:00
44 changed files with 762 additions and 76 deletions

View File

@@ -31,7 +31,7 @@ namespace Umbraco.Core.Cache
/// </summary>
/// <remarks>
/// <para>Will use HttpContext.Current.</para>
/// fixme/task: use IHttpContextAccessor NOT HttpContext.Current
/// TODO - https://github.com/umbraco/Umbraco-CMS/issues/4239 - use IHttpContextAccessor NOT HttpContext.Current
/// </remarks>
public HttpRequestAppCache()
{ }

View File

@@ -81,7 +81,7 @@ namespace Umbraco.Core.Configuration
{
try
{
// fixme/task - stop having version in web.config appSettings
// TODO - https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings
var value = ConfigurationManager.AppSettings["umbracoConfigurationStatus"];
return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null;
}

View File

@@ -118,7 +118,12 @@ namespace Umbraco.Core
/// RadioButton list.
/// </summary>
public const string RadioButtonList = "Umbraco.RadioButtonList";
/// <summary>
/// Related Links.
/// </summary>
public const string RelatedLinks = "Umbraco.RelatedLinks";
/// <summary>
/// Slider.
/// </summary>

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Umbraco.Core.Deploy
{
/// <summary>
/// Defines methods that can convert a data type configurations to / from an environment-agnostic string.
/// </summary>
/// <remarks>Configurations may contain values such as content identifiers, that would be local
/// to one environment, and need to be converted in order to be deployed.</remarks>
[SuppressMessage("ReSharper", "UnusedMember.Global", Justification = "This is actual only used by Deploy, but we dont want third parties to have references on deploy, thats why this interface is part of core.")]
public interface IDataTypeConfigurationConnector
{
/// <summary>
/// Gets the property editor aliases that the value converter supports by default.
/// </summary>
IEnumerable<string> PropertyEditorAliases { get; }
/// <summary>
/// Gets the environment-agnostic data type configurations corresponding to environment-specific configurations.
/// </summary>
/// <param name="configuration">The environment-specific configuration.</param>
/// <param name="dependencies">The dependencies.</param>
/// <returns></returns>
IDictionary<string, string> ConvertToDeploy(IDictionary<string, string> configuration, ICollection<ArtifactDependency> dependencies);
/// <summary>
/// Gets the environment-specific data type configurations corresponding to environment-agnostic configurations.
/// </summary>
/// <param name="configuration">The environment-agnostic configuration.</param>
/// <returns></returns>
IDictionary<string, string> ConvertToLocalEnvironment(IDictionary<string, string> configuration);
}
}

View File

@@ -1,32 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Deploy
{
/// <summary>
/// Defines methods that can convert a preValue to / from an environment-agnostic string.
/// </summary>
/// <remarks>PreValues may contain values such as content identifiers, that would be local
/// to one environment, and need to be converted in order to be deployed.</remarks>
public interface IPreValueConnector // fixme/task: rename to IDataTypeConfigurationConnector + kill all "preValues" name usage
{
/// <summary>
/// Gets the property editor aliases that the value converter supports by default.
/// </summary>
IEnumerable<string> PropertyEditorAliases { get; }
/// <summary>
/// Gets the environment-agnostic preValues corresponding to environment-specific preValues.
/// </summary>
/// <param name="preValues">The environment-specific preValues.</param>
/// <param name="dependencies">The dependencies.</param>
/// <returns></returns>
IDictionary<string, string> ConvertToDeploy(IDictionary<string, string> preValues, ICollection<ArtifactDependency> dependencies);
/// <summary>
/// Gets the environment-specific preValues corresponding to environment-agnostic preValues.
/// </summary>
/// <param name="preValues">The environment-agnostic preValues.</param>
/// <returns></returns>
IDictionary<string, string> ConvertToLocalEnvironment(IDictionary<string, string> preValues);
}
}

View File

@@ -135,7 +135,7 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1047, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1047", SortOrder = 2, UniqueId = new Guid("1EA2E01F-EBD8-4CE1-8D71-6B1149E63548"), Text = "Member Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Multi URL Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Related Links", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
}
private void CreateLockData()
@@ -301,7 +301,7 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1048, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1049, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext",
Configuration = "{\"multiPicker\":1}" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1050, EditorAlias = Constants.PropertyEditors.Aliases.MultiUrlPicker, DbType = "Ntext" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1050, EditorAlias = Constants.PropertyEditors.Aliases.RelatedLinks, DbType = "Ntext" });
}
private void CreateRelationTypeData()

View File

@@ -16,6 +16,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
RenameDataType(Constants.PropertyEditors.Aliases.MediaPicker + "2", Constants.PropertyEditors.Aliases.MediaPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MemberPicker + "2", Constants.PropertyEditors.Aliases.MemberPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MultiNodeTreePicker + "2", Constants.PropertyEditors.Aliases.MultiNodeTreePicker);
RenameDataType(Constants.PropertyEditors.Aliases.RelatedLinks + "2", Constants.PropertyEditors.Aliases.RelatedLinks);
RenameDataType("Umbraco.TextboxMultiple", Constants.PropertyEditors.Aliases.TextArea, false);
RenameDataType("Umbraco.Textbox", Constants.PropertyEditors.Aliases.TextBox, false);
}

View File

@@ -153,8 +153,12 @@ namespace Umbraco.Core.Models.PublishedContent
/// </remarks>
bool IsDraft(string culture = null);
// fixme/task - consider having an IsPublished flag too
// so that when IsDraft is true, we can check whether there is a published version?
/// <summary>
/// Gets a value indicating whether the content is published.
/// </summary>
/// <param name="culture"></param>
bool IsPublished(string culture = null);
#endregion

View File

@@ -111,6 +111,10 @@ namespace Umbraco.Core.Models.PublishedContent
/// <inheritdoc />
public virtual bool IsDraft(string culture = null) => _content.IsDraft(culture);
/// <inheritdoc />
public virtual bool IsPublished(string culture = null) => _content.IsPublished(culture);
#endregion
#region Tree

View File

@@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
private readonly Lazy<PropertyEditorCollection> _editors;
// fixme/task - get rid of Lazy injection and fix circular dependencies
// TODO - https://github.com/umbraco/Umbraco-CMS/issues/4237 - get rid of Lazy injection and fix circular dependencies
public DataTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, Lazy<PropertyEditorCollection> editors, ILogger logger)
: base(scopeAccessor, cache, logger)
{

View File

@@ -260,7 +260,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override void PersistNewItem(IContent entity)
{
// fixme/task - sort out IContent vs Content
// TODO: https://github.com/umbraco/Umbraco-CMS/issues/4234 - sort out IContent vs Content
// however, it's not just so we have access to AddingEntity
// there are tons of things at the end of the methods, that can only work with a true Content
// and basically, the repository requires a Content, not an IContent

View File

@@ -315,6 +315,7 @@
<Compile Include="Dashboards\AccessRuleType.cs" />
<Compile Include="Dashboards\IAccessRule.cs" />
<Compile Include="Dashboards\IDashboardSection.cs" />
<Compile Include="Deploy\IDataTypeConfigurationConnector.cs" />
<Compile Include="DisposableObjectSlim.cs" />
<Compile Include="Events\ExportedMemberEventArgs.cs" />
<Compile Include="Events\RolesEventArgs.cs" />
@@ -548,7 +549,6 @@
<Compile Include="Deploy\IImageSourceParser.cs" />
<Compile Include="Deploy\ILocalLinkParser.cs" />
<Compile Include="Deploy\IMacroParser.cs" />
<Compile Include="Deploy\IPreValueConnector.cs" />
<Compile Include="Deploy\IServiceConnector.cs" />
<Compile Include="Deploy\IUniqueIdentifyingServiceConnector.cs" />
<Compile Include="Deploy\IValueConnector.cs" />

View File

@@ -94,6 +94,7 @@ namespace Umbraco.Tests.Benchmarks
Guid key, version;
string name, urlName, writerName, creatorName, docTypeAlias, path;
bool isDraft;
bool isPublished;
DateTime createDate, updateDate;
PublishedContentType publishedContentType;
Dictionary<string, IPublishedProperty> properties;
@@ -104,7 +105,7 @@ namespace Umbraco.Tests.Benchmarks
OriginalInitializeNode(_xml10.DocumentElement, false, false,
out id, out key, out template, out sortOrder, out name, out writerName, out urlName,
out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path,
out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType,
out version, out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType,
out properties);
}
@@ -114,7 +115,7 @@ namespace Umbraco.Tests.Benchmarks
OriginalInitializeNode(_xml100.DocumentElement, false, false,
out id, out key, out template, out sortOrder, out name, out writerName, out urlName,
out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path,
out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType,
out version, out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType,
out properties);
}
@@ -124,7 +125,7 @@ namespace Umbraco.Tests.Benchmarks
OriginalInitializeNode(_xml1000.DocumentElement, false, false,
out id, out key, out template, out sortOrder, out name, out writerName, out urlName,
out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path,
out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType,
out version, out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType,
out properties);
}
@@ -134,7 +135,7 @@ namespace Umbraco.Tests.Benchmarks
OriginalInitializeNode(_xml10000.DocumentElement, false, false,
out id, out key, out template, out sortOrder, out name, out writerName, out urlName,
out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path,
out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType,
out version, out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType,
out properties);
}
@@ -144,7 +145,7 @@ namespace Umbraco.Tests.Benchmarks
XmlPublishedContent.InitializeNode(null, _xml10.DocumentElement, false,
out id, out key, out template, out sortOrder, out name, out writerName, out urlName,
out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path,
out createDate, out updateDate, out level, out isDraft, out publishedContentType,
out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType,
out properties, GetPublishedContentType);
}
@@ -154,7 +155,7 @@ namespace Umbraco.Tests.Benchmarks
XmlPublishedContent.InitializeNode(null, _xml100.DocumentElement, false,
out id, out key, out template, out sortOrder, out name, out writerName, out urlName,
out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path,
out createDate, out updateDate, out level, out isDraft, out publishedContentType,
out createDate, out updateDate, out level, out isDraft, out isPublished,out publishedContentType,
out properties, GetPublishedContentType);
}
@@ -164,7 +165,7 @@ namespace Umbraco.Tests.Benchmarks
XmlPublishedContent.InitializeNode(null, _xml1000.DocumentElement, false,
out id, out key, out template, out sortOrder, out name, out writerName, out urlName,
out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path,
out createDate, out updateDate, out level, out isDraft, out publishedContentType,
out createDate, out updateDate, out level, out isDraft, out isPublished,out publishedContentType,
out properties, GetPublishedContentType);
}
@@ -174,7 +175,7 @@ namespace Umbraco.Tests.Benchmarks
XmlPublishedContent.InitializeNode(null, _xml10000.DocumentElement, false,
out id, out key, out template, out sortOrder, out name, out writerName, out urlName,
out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path,
out createDate, out updateDate, out level, out isDraft, out publishedContentType,
out createDate, out updateDate, out level, out isDraft, out isPublished,out publishedContentType,
out properties, GetPublishedContentType);
}
@@ -182,7 +183,7 @@ namespace Umbraco.Tests.Benchmarks
internal static void OriginalInitializeNode(XmlNode xmlNode, bool legacy, bool isPreviewing,
out int id, out Guid key, out int template, out int sortOrder, out string name, out string writerName, out string urlName,
out string creatorName, out int creatorId, out int writerId, out string docTypeAlias, out int docTypeId, out string path,
out Guid version, out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft,
out Guid version, out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft, out bool isPublished,
out PublishedContentType contentType, out Dictionary<string, IPublishedProperty> properties)
{
//initialize the out params with defaults:
@@ -193,6 +194,7 @@ namespace Umbraco.Tests.Benchmarks
name = writerName = urlName = creatorName = docTypeAlias = path = null;
createDate = updateDate = default(DateTime);
isDraft = false;
isPublished = true;
contentType = null;
properties = null;

View File

@@ -279,7 +279,7 @@ AnotherContentFinder
public void GetDataEditors()
{
var types = _typeLoader.GetDataEditors();
Assert.AreEqual(39, types.Count());
Assert.AreEqual(40, types.Count());
}
/// <summary>

View File

@@ -262,6 +262,7 @@ namespace Umbraco.Tests.Published
// ReSharper disable UnassignedGetOnlyAutoProperty
public override PublishedItemType ItemType { get; }
public override bool IsDraft(string culture = null) => false;
public override bool IsPublished(string culture = null) => true;
public override IPublishedContent Parent { get; }
public override IEnumerable<IPublishedContent> Children { get; }
public override PublishedContentType ContentType { get; }

View File

@@ -217,6 +217,7 @@ namespace Umbraco.Tests.PublishedContent
public Guid Version { get; set; }
public int Level { get; set; }
public bool IsDraft(string culture = null) => false;
public bool IsPublished(string culture = null) => true;
public IEnumerable<IPublishedProperty> Properties { get; set; }

View File

@@ -192,6 +192,7 @@ namespace Umbraco.Tests.PublishedContent
public PublishedItemType ItemType { get { return PublishedItemType.Content; } }
public bool IsDraft(string culture = null) => false;
public bool IsPublished(string culture = null) => true;
#endregion

View File

@@ -2215,7 +2215,7 @@ namespace Umbraco.Tests.Services
Assert.That(sut.GetValue<Udi>("contentPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C"))));
Assert.That(sut.GetValue<Udi>("mediaPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Media, new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691"))));
Assert.That(sut.GetValue<Udi>("memberPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D"))));
Assert.That(sut.GetValue<string>("multiUrlPicker"), Is.EqualTo("[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]"));
Assert.That(sut.GetValue<string>("relatedLinks"), Is.EqualTo("<links><link title=\"google\" link=\"http://google.com\" type=\"external\" newwindow=\"0\" /></links>"));
Assert.That(sut.GetValue<string>("tags"), Is.EqualTo("this,is,tags"));
}

View File

@@ -132,7 +132,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
content.SetValue("contentPicker", Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")).ToString());
content.SetValue("mediaPicker", Udi.Create(Constants.UdiEntityType.Media, new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691")).ToString());
content.SetValue("memberPicker", Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")).ToString());
content.SetValue("multiUrlPicker", "[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]");
content.SetValue("relatedLinks", "<links><link title=\"google\" link=\"http://google.com\" type=\"external\" newwindow=\"0\" /></links>");
content.SetValue("tags", "this,is,tags");
return content;

View File

@@ -370,7 +370,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.ContentPicker, ValueStorageType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeId = 1046 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MediaPicker, ValueStorageType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeId = 1048 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MemberPicker, ValueStorageType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeId = 1047 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MultiUrlPicker, ValueStorageType.Nvarchar) { Alias = "multiUrlPicker", Name = "Multi URL Picker", Mandatory = false, SortOrder = 21, DataTypeId = 1050 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.RelatedLinks, ValueStorageType.Ntext) { Alias = "relatedLinks", Name = "Related Links", Mandatory = false, SortOrder = 21, DataTypeId = 1050 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Tags, ValueStorageType.Ntext) { Alias = "tags", Name = "Tags", Mandatory = false, SortOrder = 22, DataTypeId = 1041 });
contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 });

View File

@@ -48,6 +48,7 @@ namespace Umbraco.Tests.TestHelpers.Stubs
public string GetUrl(string culture = null) => throw new NotSupportedException();
public PublishedItemType ItemType => ContentType.ItemType;
public bool IsDraft(string culture = null) => false;
public bool IsPublished(string culture = null) => true;
public IPublishedContent Parent { get; set; }
public IEnumerable<IPublishedContent> Children { get; set; }

View File

@@ -29,5 +29,30 @@ namespace Umbraco.Tests.Web.Mvc
var output = _htmlHelper.Wrap("div", "hello world", new {style = "color:red;", onclick = "void();"});
Assert.AreEqual("<div style=\"color:red;\" onclick=\"void();\">hello world</div>", output.ToHtmlString());
}
[Test]
public void GetRelatedLinkHtml_Simple()
{
var relatedLink = new Umbraco.Web.Models.RelatedLink {
Caption = "Link Caption",
NewWindow = true,
Link = "https://www.google.com/"
};
var output = _htmlHelper.GetRelatedLinkHtml(relatedLink);
Assert.AreEqual("<a href=\"https://www.google.com/\" target=\"_blank\">Link Caption</a>", output.ToHtmlString());
}
[Test]
public void GetRelatedLinkHtml_HtmlAttributes()
{
var relatedLink = new Umbraco.Web.Models.RelatedLink
{
Caption = "Link Caption",
NewWindow = true,
Link = "https://www.google.com/"
};
var output = _htmlHelper.GetRelatedLinkHtml(relatedLink, new { @class = "test-class"});
Assert.AreEqual("<a class=\"test-class\" href=\"https://www.google.com/\" target=\"_blank\">Link Caption</a>", output.ToHtmlString());
}
}
}

View File

@@ -13,6 +13,10 @@
cursor: pointer;
justify-content: space-between;
color: @black;
&:hover .umb-expansion-panel__expand {
color: @gray-6;
}
}
.umb-expansion-panel__expand {
@@ -22,4 +26,4 @@
.umb-expansion-panel__content {
padding: 20px;
border-top: 1px solid @gray-9;
}
}

View File

@@ -1,16 +1,13 @@
using System.Runtime.Serialization;
using System.Web.Http;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
namespace Umbraco.Web.Editors
{
// fixme/task - deal with this
// this is not authenticated, and therefore public, and therefore reveals we
// are running Umbraco - but, all requests should come from localhost really,
// so there should be a way to 404 when the request comes from the outside.
public class KeepAliveController : UmbracoApiController
{
[OnlyLocalRequests]
[HttpGet]
public KeepAlivePingResult Ping()
{

View File

@@ -830,5 +830,39 @@ namespace Umbraco.Web
}
#endregion
#region RelatedLink
/// <summary>
/// Renders an anchor element for a RelatedLink instance.
/// Format: &lt;a href=&quot;relatedLink.Link&quot; target=&quot;_blank/_self&quot;&gt;relatedLink.Caption&lt;/a&gt;
/// </summary>
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
/// <param name="relatedLink">The RelatedLink instance</param>
/// <returns>An anchor element </returns>
public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink)
{
return htmlHelper.GetRelatedLinkHtml(relatedLink, null);
}
/// <summary>
/// Renders an anchor element for a RelatedLink instance, accepting htmlAttributes.
/// Format: &lt;a href=&quot;relatedLink.Link&quot; target=&quot;_blank/_self&quot; htmlAttributes&gt;relatedLink.Caption&lt;/a&gt;
/// </summary>
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
/// <param name="relatedLink">The RelatedLink instance</param>
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
/// <returns></returns>
public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink, object htmlAttributes)
{
var tagBuilder = new TagBuilder("a");
tagBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
tagBuilder.MergeAttribute("href", relatedLink.Link);
tagBuilder.MergeAttribute("target", relatedLink.NewWindow ? "_blank" : "_self");
tagBuilder.InnerHtml = HttpUtility.HtmlEncode(relatedLink.Caption);
return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
}
#endregion
}
}

View File

@@ -144,6 +144,8 @@ namespace Umbraco.Web.Models
/// <inheritdoc />
public abstract bool IsDraft(string culture = null);
public abstract bool IsPublished(string culture = null);
#endregion
#region Tree

View File

@@ -0,0 +1,11 @@
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models
{
public class RelatedLink : RelatedLinkBase
{
public int? Id { get; internal set; }
internal bool IsDeleted { get; set; }
public IPublishedContent Content { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using Newtonsoft.Json;
namespace Umbraco.Web.Models
{
public abstract class RelatedLinkBase
{
[JsonProperty("caption")]
public string Caption { get; set; }
[JsonProperty("link")]
public string Link { get; set; }
[JsonProperty("newWindow")]
public bool NewWindow { get; set; }
[JsonProperty("isInternal")]
public bool IsInternal { get; set; }
[JsonProperty("type")]
public RelatedLinkType Type { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RelatedLinkType.cs" company="Umbraco">
// Umbraco
// </copyright>
// <summary>
// Defines the RelatedLinkType type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Umbraco.Web.Models
{
/// <summary>
/// The related link type.
/// </summary>
public enum RelatedLinkType
{
/// <summary>
/// Internal link type
/// </summary>
Internal,
/// <summary>
/// External link type
/// </summary>
External
}
}

View File

@@ -0,0 +1,42 @@
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Umbraco.Web.Models
{
[TypeConverter(typeof(RelatedLinksTypeConverter))]
public class RelatedLinks : IEnumerable<RelatedLink>
{
private readonly string _propertyData;
private readonly IEnumerable<RelatedLink> _relatedLinks;
public RelatedLinks(IEnumerable<RelatedLink> relatedLinks, string propertyData)
{
_relatedLinks = relatedLinks;
_propertyData = propertyData;
}
/// <summary>
/// Gets the property data.
/// </summary>
internal string PropertyData
{
get
{
return this._propertyData;
}
}
public IEnumerator<RelatedLink> GetEnumerator()
{
return _relatedLinks.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
}

View File

@@ -0,0 +1,20 @@
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace Umbraco.Web.Mvc
{
public class OnlyLocalRequestsAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.Request.IsLocal())
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
}
}

View File

@@ -0,0 +1,13 @@
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// Represents the configuration for the related links value editor.
/// </summary>
public class RelatedLinksConfiguration
{
[ConfigurationField("max", "Maximum number of links", "number", Description = "Enter the maximum amount of links to be added, enter 0 for unlimited")]
public int Maximum { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using System.Collections.Generic;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// Represents the configuration editor for the related links value editor.
/// </summary>
public class RelatedLinksConfigurationEditor : ConfigurationEditor
{
public override IDictionary<string, object> ToValueEditor(object configuration)
{
var d = base.ToValueEditor(configuration);
d["idType"] = "udi";
return d;
}
}
}

View File

@@ -0,0 +1,16 @@
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[DataEditor(Constants.PropertyEditors.Aliases.RelatedLinks, "Related links", "relatedlinks", ValueType = ValueTypes.Json, Icon = "icon-thumbnail-list", Group = "pickers")]
public class RelatedLinksPropertyEditor : DataEditor
{
public RelatedLinksPropertyEditor(ILogger logger)
: base(logger)
{ }
protected override IConfigurationEditor CreateConfigurationEditor() => new RelatedLinksConfigurationEditor();
}
}

View File

@@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Services;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
public class RelatedLinksLegacyValueConverter : PropertyValueConverterBase
{
private static readonly string[] MatchingEditors = {
Constants.PropertyEditors.Aliases.RelatedLinks
};
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ILogger _logger;
private readonly ServiceContext _services;
public RelatedLinksLegacyValueConverter(IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, ILogger logger)
{
_umbracoContextAccessor = umbracoContextAccessor;
_services = services;
_logger = logger;
}
public override bool IsConverter(PublishedPropertyType propertyType)
=> MatchingEditors.Contains(propertyType.EditorAlias);
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
=> typeof (JArray);
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
=> PropertyCacheLevel.Element;
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();
if (sourceString.DetectIsJson())
{
try
{
var obj = JsonConvert.DeserializeObject<JArray>(sourceString);
//update the internal links if we have a context
if (UmbracoContext.Current != null)
{
var helper = new UmbracoHelper(_umbracoContextAccessor.UmbracoContext, _services);
foreach (var a in obj)
{
var type = a.Value<string>("type");
if (type.IsNullOrWhiteSpace() == false)
{
if (type == "internal")
{
switch (propertyType.EditorAlias)
{
case Constants.PropertyEditors.Aliases.RelatedLinks:
var strLinkId = a.Value<string>("link");
var udiAttempt = strLinkId.TryConvertTo<Udi>();
if (udiAttempt)
{
var content = helper.PublishedContent(udiAttempt.Result);
if (content == null) break;
a["link"] = helper.Url(content.Id);
}
break;
}
}
}
}
}
return obj;
}
catch (Exception ex)
{
_logger.Error<RelatedLinksLegacyValueConverter>(ex, "Could not parse the string '{Json}' to a json object", sourceString);
}
}
//it's not json, just return the string
return sourceString;
}
public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();
if (sourceString.DetectIsJson())
{
try
{
var obj = JsonConvert.DeserializeObject<Array>(sourceString);
var d = new XmlDocument();
var e = d.CreateElement("links");
d.AppendChild(e);
foreach (dynamic link in obj)
{
var ee = d.CreateElement("link");
ee.SetAttribute("title", link.title);
ee.SetAttribute("link", link.link);
ee.SetAttribute("type", link.type);
ee.SetAttribute("newwindow", link.newWindow);
e.AppendChild(ee);
}
return d.CreateNavigator();
}
catch (Exception ex)
{
_logger.Error<RelatedLinksLegacyValueConverter>(ex, "Could not parse the string '{Json}' to a json object", sourceString);
}
}
//it's not json, just return the string
return sourceString;
}
}
}

View File

@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Web.Models;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
/// <summary>
/// The related links property value converter.
/// </summary>
[DefaultPropertyValueConverter(typeof(RelatedLinksLegacyValueConverter), typeof(JsonValueConverter))]
public class RelatedLinksValueConverter : PropertyValueConverterBase
{
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ILogger _logger;
public RelatedLinksValueConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor, IUmbracoContextAccessor umbracoContextAccessor, ILogger logger)
{
_publishedSnapshotAccessor = publishedSnapshotAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
_logger = logger;
}
/// <summary>
/// Checks if this converter can convert the property editor and registers if it can.
/// </summary>
/// <param name="propertyType">
/// The property type.
/// </param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public override bool IsConverter(PublishedPropertyType propertyType)
=> propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.RelatedLinks);
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
=> typeof (JArray);
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
=> PropertyCacheLevel.Element;
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();
var relatedLinksData = JsonConvert.DeserializeObject<IEnumerable<RelatedLink>>(sourceString);
var relatedLinks = new List<RelatedLink>();
foreach (var linkData in relatedLinksData)
{
var relatedLink = new RelatedLink
{
Caption = linkData.Caption,
NewWindow = linkData.NewWindow,
IsInternal = linkData.IsInternal,
Type = linkData.Type,
Link = linkData.Link
};
int contentId;
if (int.TryParse(relatedLink.Link, out contentId))
{
relatedLink.Id = contentId;
relatedLink = CreateLink(relatedLink);
}
else
{
var strLinkId = linkData.Link;
var udiAttempt = strLinkId.TryConvertTo<GuidUdi>();
if (udiAttempt.Success && udiAttempt.Result != null)
{
var content = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(udiAttempt.Result.Guid);
if (content != null)
{
relatedLink.Id = content.Id;
relatedLink = CreateLink(relatedLink);
relatedLink.Content = content;
}
}
}
if (relatedLink.IsDeleted == false)
{
relatedLinks.Add(relatedLink);
}
else
{
_logger.Warn<RelatedLinksValueConverter>("Related Links value converter skipped a link as the node has been unpublished/deleted (Internal Link NodeId: {RelatedLinkNodeId}, Link Caption: '{RelatedLinkCaption}')", relatedLink.Link, relatedLink.Caption);
}
}
return new RelatedLinks(relatedLinks, sourceString);
}
private RelatedLink CreateLink(RelatedLink link)
{
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
if (link.IsInternal && link.Id != null)
{
if (umbracoContext == null)
return null;
var urlProvider = umbracoContext.UrlProvider;
link.Link = urlProvider.GetUrl((int)link.Id);
if (link.Link.Equals("#"))
{
link.IsDeleted = true;
link.Link = link.Id.ToString();
}
else
{
link.IsDeleted = false;
}
}
return link;
}
public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
if (inter == null) return null;
var sourceString = inter.ToString();
if (sourceString.DetectIsJson())
{
try
{
var obj = JsonConvert.DeserializeObject<Array>(sourceString);
var d = new XmlDocument();
var e = d.CreateElement("links");
d.AppendChild(e);
foreach (dynamic link in obj)
{
var ee = d.CreateElement("link");
ee.SetAttribute("title", link.title);
ee.SetAttribute("link", link.link);
ee.SetAttribute("type", link.type);
ee.SetAttribute("newwindow", link.newWindow);
e.AppendChild(ee);
}
return d.CreateNavigator();
}
catch (Exception ex)
{
_logger.Error<RelatedLinksValueConverter>(ex, "Could not parse the string {Json} to a json object", sourceString);
}
}
//it's not json, just return the string
return sourceString;
}
}
}

View File

@@ -293,6 +293,23 @@ namespace Umbraco.Web.PublishedCache.NuCache
return _contentData.CultureInfos.TryGetValue(culture, out var cvar) && cvar.IsDraft;
}
public override bool IsPublished(string culture = null)
{
if (!ContentType.VariesByCulture())
{
return _contentData.Published;
}
// handle context culture
if (culture == null)
{
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
}
//If the current culture is not a draft, it must be the published version
return _contentData.CultureInfos.TryGetValue(culture, out var cvar) && !cvar.IsDraft;
}
#endregion
#region Tree

View File

@@ -78,6 +78,8 @@ namespace Umbraco.Web.PublishedCache
public override bool IsDraft(string culture = null) => false;
public override bool IsPublished(string culture = null) => true;
public override IPublishedContent Parent => null;
public override IEnumerable<IPublishedContent> Children => Enumerable.Empty<IPublishedContent>();

View File

@@ -179,6 +179,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
public override bool IsDraft(string culture = null) => false;
public override bool IsPublished(string culture = null) => true;
public override IEnumerable<IPublishedProperty> Properties => _properties;
public override IEnumerable<IPublishedContent> Children => _getChildren.Value;

View File

@@ -63,6 +63,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
private int _sortOrder;
private int _level;
private bool _isDraft;
private bool _isPublished;
public override IEnumerable<IPublishedContent> Children
{
@@ -228,6 +229,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
return _isDraft; // bah
}
public override bool IsPublished(string culture = null)
{
EnsureNodeInitialized();
return _isPublished;
}
public override IEnumerable<IPublishedProperty> Properties
{
get
@@ -280,7 +287,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
InitializeNode(this, _xmlNode, _isPreviewing,
out _id, out _key, out _template, out _sortOrder, out _name, out _writerName,
out _urlName, out _creatorName, out _creatorId, out _writerId, out _docTypeAlias, out _docTypeId, out _path,
out _createDate, out _updateDate, out _level, out _isDraft, out _contentType, out _properties,
out _createDate, out _updateDate, out _level, out _isDraft, out _isPublished, out _contentType, out _properties,
_contentTypeCache.Get);
_nodeInitialized = true;
@@ -290,7 +297,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
internal static void InitializeNode(XmlPublishedContent node, XmlNode xmlNode, bool isPreviewing,
out int id, out Guid key, out int template, out int sortOrder, out string name, out string writerName, out string urlName,
out string creatorName, out int creatorId, out int writerId, out string docTypeAlias, out int docTypeId, out string path,
out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft,
out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft,out bool isPublished,
out PublishedContentType contentType, out Dictionary<string, IPublishedProperty> properties,
Func<PublishedItemType, string, PublishedContentType> getPublishedContentType)
{
@@ -302,6 +309,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
name = writerName = urlName = creatorName = docTypeAlias = path = null;
createDate = updateDate = default(DateTime);
isDraft = false;
isPublished = false;
contentType = null;
properties = null;

View File

@@ -799,7 +799,7 @@ namespace Umbraco.Web
return content.DescendantsOrSelf(false, p => p.Level >= level, culture);
}
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, string contentTypeAlias, string culture = null)
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, string contentTypeAlias, string culture)
{
return content.DescendantsOrSelf(false, p => p.ContentType.Alias == contentTypeAlias, culture);
}
@@ -826,7 +826,7 @@ namespace Umbraco.Web
return content.DescendantsOrSelf(true, p => p.Level >= level, culture);
}
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, string contentTypeAlias, string culture = null)
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, string contentTypeAlias, string culture)
{
return content.DescendantsOrSelf(true, p => p.ContentType.Alias == contentTypeAlias, culture);
}
@@ -853,7 +853,7 @@ namespace Umbraco.Web
return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.Level == level);
}
public static IPublishedContent Descendant(this IPublishedContent content, string contentTypeAlias, string culture = null)
public static IPublishedContent Descendant(this IPublishedContent content, string contentTypeAlias, string culture)
{
return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias);
}
@@ -880,7 +880,7 @@ namespace Umbraco.Web
return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.Level == level);
}
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string contentTypeAlias, string culture = null)
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string contentTypeAlias, string culture)
{
return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias);
}
@@ -954,14 +954,7 @@ namespace Umbraco.Web
/// </remarks>
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, string culture = null)
{
if (content == null) throw new ArgumentNullException(nameof(content)); // fixme/task wtf is this?
return content.Children.Where(x =>
{
if (!x.ContentType.VariesByCulture()) return true; // invariant = always ok
return x.HasCulture(culture);
return false;
});
if (content == null) throw new ArgumentNullException(nameof(content));
return content.Children.WhereIsInvariantOrHasCulture(culture);
}
@@ -1017,7 +1010,7 @@ namespace Umbraco.Web
/// <summary>
/// Gets the first child of the content, of a given content type.
/// </summary>
public static IPublishedContent FirstChild(this IPublishedContent content, string alias, string culture = null) // fixme/task oops
public static IPublishedContent FirstChild(this IPublishedContent content, string alias, string culture)
{
return content.Children(culture,alias).FirstOrDefault();
}

View File

@@ -0,0 +1,98 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Composing;
using Umbraco.Web.Models;
namespace Umbraco.Web
{
public class RelatedLinksTypeConverter : TypeConverter
{
private readonly UmbracoHelper _umbracoHelper;
public RelatedLinksTypeConverter(UmbracoHelper umbracoHelper)
{
_umbracoHelper = umbracoHelper;
}
public RelatedLinksTypeConverter()
{
}
private static readonly Type[] ConvertableTypes = new[]
{
typeof(JArray)
};
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return ConvertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, destinationType))
|| base.CanConvertFrom(context, destinationType);
}
public override object ConvertTo(
ITypeDescriptorContext context,
CultureInfo culture,
object value,
Type destinationType)
{
var relatedLinks = value as RelatedLinks;
if (relatedLinks == null)
return null;
if (TypeHelper.IsTypeAssignableFrom<JArray>(destinationType))
{
// Conversion to JArray taken from old value converter
var obj = JsonConvert.DeserializeObject<JArray>(relatedLinks.PropertyData);
var umbracoHelper = GetUmbracoHelper();
//update the internal links if we have a context
if (umbracoHelper != null)
{
foreach (var a in obj)
{
var type = a.Value<string>("type");
if (type.IsNullOrWhiteSpace() == false)
{
if (type == "internal")
{
var linkId = a.Value<int>("link");
var link = umbracoHelper.Url(linkId);
a["link"] = link;
}
}
}
}
return obj;
}
return base.ConvertTo(context, culture, value, destinationType);
}
private UmbracoHelper GetUmbracoHelper()
{
if (_umbracoHelper != null)
return _umbracoHelper;
if (UmbracoContext.Current == null)
{
Current.Logger.Warn<RelatedLinksTypeConverter>("Cannot create an UmbracoHelper the UmbracoContext is null");
return null;
}
//DO NOT assign to _umbracoHelper variable, this is a singleton class and we cannot assign this based on an UmbracoHelper which is request based
return new UmbracoHelper(UmbracoContext.Current, Current.Services);
}
}
}

View File

@@ -186,6 +186,7 @@
<Compile Include="Services\IDashboardService.cs" />
<Compile Include="Models\Link.cs" />
<Compile Include="Models\LinkType.cs" />
<Compile Include="Mvc\OnlyLocalRequestsAttribute.cs" />
<Compile Include="PropertyEditors\MultiUrlPickerConfiguration.cs" />
<Compile Include="PropertyEditors\MultiUrlPickerConfigurationEditor.cs" />
<Compile Include="PropertyEditors\MultiUrlPickerPropertyEditor.cs" />
@@ -417,6 +418,10 @@
<Compile Include="Models\Mapping\ContentItemDisplayVariationResolver.cs" />
<Compile Include="Models\PublishedContent\HttpContextVariationContextAccessor.cs" />
<Compile Include="Models\PublishedContent\PublishedValueFallback.cs" />
<Compile Include="Models\RelatedLink.cs" />
<Compile Include="Models\RelatedLinkBase.cs" />
<Compile Include="Models\RelatedLinks.cs" />
<Compile Include="Models\RelatedLinkType.cs" />
<Compile Include="Models\SendCodeViewModel.cs" />
<Compile Include="Models\Trees\ExportMember.cs" />
<Compile Include="Models\UserTourStatus.cs" />
@@ -462,6 +467,9 @@
<Compile Include="PropertyEditors\NestedContentPropertyEditor.cs" />
<Compile Include="PropertyEditors\ParameterEditors\MultipleContentPickerParameterEditor.cs" />
<Compile Include="PropertyEditors\PropertyEditorsComponent.cs" />
<Compile Include="PropertyEditors\RelatedLinksPropertyEditor.cs" />
<Compile Include="PropertyEditors\RelatedLinksConfiguration.cs" />
<Compile Include="PropertyEditors\RelatedLinksConfigurationEditor.cs" />
<Compile Include="PropertyEditors\RichTextConfiguration.cs" />
<Compile Include="PropertyEditors\SliderConfigurationEditor.cs" />
<Compile Include="PropertyEditors\TagConfigurationEditor.cs" />
@@ -477,6 +485,7 @@
<Compile Include="PropertyEditors\ValueConverters\NestedContentManyValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\NestedContentValueConverterBase.cs" />
<Compile Include="PropertyEditors\ValueConverters\NestedContentSingleValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\RelatedLinksLegacyValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\MediaPickerValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\MemberPickerValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\MultiNodeTreePickerValueConverter.cs" />
@@ -540,6 +549,7 @@
<Compile Include="PublishedCache\XmlPublishedCache\XmlStoreFilePersister.cs" />
<Compile Include="PublishedElementExtensions.cs" />
<Compile Include="PublishedModels\DummyClassSoThatPublishedModelsNamespaceExists.cs" />
<Compile Include="RelatedLinksTypeConverter.cs" />
<Compile Include="Routing\ContentFinderByUrl.cs" />
<Compile Include="Routing\ContentFinderByUrlAndTemplate.cs" />
<Compile Include="Routing\ContentFinderCollection.cs" />
@@ -862,6 +872,7 @@
<Compile Include="PropertyEditors\TagsPropertyEditor.cs" />
<Compile Include="PropertyEditors\UploadFileTypeValidator.cs" />
<Compile Include="PropertyEditors\UserPickerPropertyEditor.cs" />
<Compile Include="PropertyEditors\ValueConverters\RelatedLinksValueConverter.cs" />
<Compile Include="PropertyEditors\ValueListConfigurationEditor.cs" />
<Compile Include="PublishedContentQuery.cs" />
<Compile Include="ImageCropperTemplateExtensions.cs" />

View File

@@ -469,6 +469,11 @@ namespace umbraco
throw new NotImplementedException();
}
public bool IsPublished(string culture = null)
{
throw new NotImplementedException();
}
public IPublishedContent Parent
{
get { return _parent; }