Files
Umbraco-CMS/src/Umbraco.Web/PublishedContentExtensions.cs

837 lines
40 KiB
C#
Raw Normal View History

2018-06-29 19:52:40 +02:00
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using Examine;
using Umbraco.Core;
2018-09-06 13:07:09 +02:00
using Umbraco.Core.Models.PublishedContent;
2018-06-29 19:52:40 +02:00
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Examine;
2018-06-29 19:52:40 +02:00
using Umbraco.Web.Composing;
2019-03-05 13:02:59 +01:00
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
2018-06-29 19:52:40 +02:00
namespace Umbraco.Web
{
/// <summary>
/// Provides extension methods for <c>IPublishedContent</c>.
/// </summary>
public static class PublishedContentExtensions
{
// see notes in PublishedElementExtensions
// (yes, this is not pretty, but works for now)
2018-06-29 19:52:40 +02:00
//
private static IPublishedValueFallback PublishedValueFallback => Current.PublishedValueFallback;
2019-03-05 13:02:59 +01:00
private static IPublishedSnapshot PublishedSnapshot => Current.PublishedSnapshot;
private static UmbracoContext UmbracoContext => Current.UmbracoContext;
private static ISiteDomainHelper SiteDomainHelper => Current.Factory.GetInstance<ISiteDomainHelper>();
private static IVariationContextAccessor VariationContextAccessor => Current.VariationContextAccessor;
2018-06-29 19:52:40 +02:00
2019-04-16 20:03:07 +02:00
#region IsComposedOf
2018-06-29 19:52:40 +02:00
/// <summary>
2019-04-16 20:03:07 +02:00
/// Gets a value indicating whether the content is of a content type composed of the given alias
2018-06-29 19:52:40 +02:00
/// </summary>
/// <param name="content">The content.</param>
2019-04-16 20:03:07 +02:00
/// <param name="alias">The content type alias.</param>
/// <returns>A value indicating whether the content is of a content type composed of a content type identified by the alias.</returns>
public static bool IsComposedOf(this IPublishedContent content, string alias)
2018-06-29 19:52:40 +02:00
{
return content.ContentType.CompositionAliases.InvariantContains(alias);
2018-06-29 19:52:40 +02:00
}
2019-04-16 20:03:07 +02:00
#endregion
#region Template
2018-06-29 19:52:40 +02:00
/// <summary>
2019-04-16 20:03:07 +02:00
/// Returns the current template Alias
2018-06-29 19:52:40 +02:00
/// </summary>
2019-04-16 20:03:07 +02:00
/// <param name="content"></param>
/// <returns>Empty string if none is set.</returns>
public static string GetTemplateAlias(this IPublishedContent content)
2018-06-29 19:52:40 +02:00
{
2019-04-16 20:03:07 +02:00
if(content.TemplateId.HasValue == false)
2018-06-29 19:52:40 +02:00
{
2019-04-16 20:03:07 +02:00
return string.Empty;
2018-06-29 19:52:40 +02:00
}
2019-04-16 20:03:07 +02:00
var template = Current.Services.FileService.GetTemplate(content.TemplateId.Value);
return template == null ? string.Empty : template.Alias;
2018-06-29 19:52:40 +02:00
}
2018-09-06 13:07:09 +02:00
public static bool IsAllowedTemplate(this IPublishedContent content, int templateId)
{
2019-01-21 14:27:11 +01:00
if (Current.Configs.Settings().WebRouting.DisableAlternativeTemplates)
2018-09-06 13:07:09 +02:00
return content.TemplateId == templateId;
2019-01-21 14:27:11 +01:00
if (content.TemplateId == templateId || !Current.Configs.Settings().WebRouting.ValidateAlternativeTemplates)
return true;
2018-09-06 13:07:09 +02:00
2019-01-21 14:27:11 +01:00
var publishedContentContentType = Current.Services.ContentTypeService.Get(content.ContentType.Id);
if (publishedContentContentType == null)
throw new NullReferenceException("No content type returned for published content (contentType='" + content.ContentType.Id + "')");
return publishedContentContentType.IsAllowedTemplate(templateId);
2018-09-06 13:07:09 +02:00
}
public static bool IsAllowedTemplate(this IPublishedContent content, string templateAlias)
{
2018-09-06 14:10:10 +02:00
var template = Current.Services.FileService.GetTemplate(templateAlias);
return template != null && content.IsAllowedTemplate(template.Id);
2018-09-06 13:07:09 +02:00
}
#endregion
#region HasValue, Value, Value<T>
2018-06-29 19:52:40 +02:00
/// <summary>
/// Gets a value indicating whether the content has a value for a property identified by its alias.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
/// <param name="culture">The variation language.</param>
/// <param name="segment">The variation segment.</param>
/// <param name="fallback">Optional fallback strategy.</param>
2018-06-29 19:52:40 +02:00
/// <returns>A value indicating whether the content has a value for the property identified by the alias.</returns>
/// <remarks>Returns true if HasValue is true, or a fallback strategy can provide a value.</remarks>
public static bool HasValue(this IPublishedContent content, string alias, string culture = null, string segment = null, Fallback fallback = default)
2018-06-29 19:52:40 +02:00
{
var property = content.GetProperty(alias);
2018-06-29 19:52:40 +02:00
// if we have a property, and it has a value, return that value
if (property != null && property.HasValue(culture, segment))
return true;
2018-06-29 19:52:40 +02:00
// else let fallback try to get a value
2019-01-21 14:27:11 +01:00
return PublishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, null, out _, out _);
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value.
2018-06-29 19:52:40 +02:00
/// </summary>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
/// <param name="culture">The variation language.</param>
/// <param name="segment">The variation segment.</param>
2018-07-24 13:32:29 +02:00
/// <param name="fallback">Optional fallback strategy.</param>
2018-10-03 10:31:35 +02:00
/// <param name="defaultValue">The default value.</param>
2018-06-29 19:52:40 +02:00
/// <returns>The value of the content's property identified by the alias, if it exists, otherwise a default value.</returns>
2018-10-03 10:31:35 +02:00
public static object Value(this IPublishedContent content, string alias, string culture = null, string segment = null, Fallback fallback = default, object defaultValue = default)
2018-06-29 19:52:40 +02:00
{
var property = content.GetProperty(alias);
2018-10-03 10:31:35 +02:00
// if we have a property, and it has a value, return that value
2018-06-29 19:52:40 +02:00
if (property != null && property.HasValue(culture, segment))
return property.GetValue(culture, segment);
2018-10-03 10:31:35 +02:00
// else let fallback try to get a value
2019-01-21 14:27:11 +01:00
if (PublishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out var value, out property))
2018-10-03 10:31:35 +02:00
return value;
// else... if we have a property, at least let the converter return its own
// vision of 'no value' (could be an empty enumerable)
2019-01-21 14:27:11 +01:00
return property?.GetValue(culture, segment);
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets the value of a content's property identified by its alias, converted to a specified type.
2018-06-29 19:52:40 +02:00
/// </summary>
/// <typeparam name="T">The target property type.</typeparam>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
/// <param name="culture">The variation language.</param>
/// <param name="segment">The variation segment.</param>
2018-07-24 13:32:29 +02:00
/// <param name="fallback">Optional fallback strategy.</param>
2018-10-03 10:31:35 +02:00
/// <param name="defaultValue">The default value.</param>
2018-06-29 19:52:40 +02:00
/// <returns>The value of the content's property identified by the alias, converted to the specified type.</returns>
2018-10-03 10:31:35 +02:00
public static T Value<T>(this IPublishedContent content, string alias, string culture = null, string segment = null, Fallback fallback = default, T defaultValue = default)
2018-06-29 19:52:40 +02:00
{
var property = content.GetProperty(alias);
2018-10-03 10:31:35 +02:00
// if we have a property, and it has a value, return that value
2018-06-29 19:52:40 +02:00
if (property != null && property.HasValue(culture, segment))
return property.Value<T>(culture, segment);
2018-10-03 10:31:35 +02:00
// else let fallback try to get a value
2019-01-21 14:27:11 +01:00
if (PublishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out var value, out property))
2018-10-03 10:31:35 +02:00
return value;
// else... if we have a property, at least let the converter return its own
// vision of 'no value' (could be an empty enumerable) - otherwise, default
return property == null ? default : property.Value<T>(culture, segment);
2018-06-29 19:52:40 +02:00
}
#endregion
2018-07-30 10:10:01 +02:00
#region Variations
/// <summary>
/// Gets the culture assigned to a document by domains, in the context of a current Uri.
/// </summary>
/// <param name="content">The document.</param>
/// <param name="current">An optional current Uri.</param>
/// <returns>The culture assigned to the document by domains.</returns>
/// <remarks>
/// <para>In 1:1 multilingual setup, a document contains several cultures (there is not
/// one document per culture), and domains, withing the context of a current Uri, assign
/// a culture to that document.</para>
/// </remarks>
public static string GetCultureFromDomains(this IPublishedContent content, Uri current = null)
{
var umbracoContext = UmbracoContext;
if (umbracoContext == null)
throw new InvalidOperationException("A current UmbracoContext is required.");
return DomainUtilities.GetCultureFromDomains(content.Id, content.Path, current, umbracoContext, SiteDomainHelper);
}
2018-07-30 10:10:01 +02:00
#endregion
2018-06-29 19:52:40 +02:00
#region Search
public static IEnumerable<PublishedSearchResult> SearchDescendants(this IPublishedContent content, string term, string indexName = null)
2018-06-29 19:52:40 +02:00
{
// TODO: inject examine manager
2018-06-29 19:52:40 +02:00
indexName = string.IsNullOrEmpty(indexName) ? Constants.UmbracoIndexes.ExternalIndexName : indexName;
if (!ExamineManager.Instance.TryGetIndex(indexName, out var index))
throw new InvalidOperationException("No index found with name " + indexName);
2018-06-29 19:52:40 +02:00
var searcher = index.GetSearcher();
2018-06-29 19:52:40 +02:00
//var t = term.Escape().Value;
//var luceneQuery = "+__Path:(" + content.Path.Replace("-", "\\-") + "*) +" + t;
2018-06-29 19:52:40 +02:00
var query = searcher.CreateQuery()
.Field(UmbracoExamineIndex.IndexPathFieldName, (content.Path + ",").MultipleCharacterWildcard())
.And()
.ManagedQuery(term);
2018-06-29 19:52:40 +02:00
return query.Execute().ToPublishedSearchResults(Current.UmbracoContext.Content);
2018-06-29 19:52:40 +02:00
}
public static IEnumerable<PublishedSearchResult> SearchChildren(this IPublishedContent content, string term, string indexName = null)
2018-06-29 19:52:40 +02:00
{
// TODO: inject examine manager
2018-06-29 19:52:40 +02:00
indexName = string.IsNullOrEmpty(indexName) ? Constants.UmbracoIndexes.ExternalIndexName : indexName;
if (!ExamineManager.Instance.TryGetIndex(indexName, out var index))
throw new InvalidOperationException("No index found with name " + indexName);
2018-06-29 19:52:40 +02:00
var searcher = index.GetSearcher();
2018-06-29 19:52:40 +02:00
//var t = term.Escape().Value;
//var luceneQuery = "+parentID:" + content.Id + " +" + t;
2018-06-29 19:52:40 +02:00
var query = searcher.CreateQuery()
.Field("parentID", content.Id)
.And()
.ManagedQuery(term);
2018-06-29 19:52:40 +02:00
return query.Execute().ToPublishedSearchResults(Current.UmbracoContext.Content);
2018-06-29 19:52:40 +02:00
}
#endregion
#region IsSomething: misc.
/// <summary>
/// Determines whether the specified content is a specified content type.
/// </summary>
/// <param name="content">The content to determine content type of.</param>
/// <param name="docTypeAlias">The alias of the content type to test against.</param>
/// <returns>True if the content is of the specified content type; otherwise false.</returns>
public static bool IsDocumentType(this IPublishedContent content, string docTypeAlias)
{
return content.ContentType.Alias.InvariantEquals(docTypeAlias);
}
/// <summary>
/// Determines whether the specified content is a specified content type or it's derived types.
/// </summary>
/// <param name="content">The content to determine content type of.</param>
/// <param name="docTypeAlias">The alias of the content type to test against.</param>
/// <param name="recursive">When true, recurses up the content type tree to check inheritance; when false just calls IsDocumentType(this IPublishedContent content, string docTypeAlias).</param>
/// <returns>True if the content is of the specified content type or a derived content type; otherwise false.</returns>
public static bool IsDocumentType(this IPublishedContent content, string docTypeAlias, bool recursive)
{
if (content.IsDocumentType(docTypeAlias))
return true;
return recursive && content.IsComposedOf(docTypeAlias);
}
#endregion
#region IsSomething: equality
public static bool IsEqual(this IPublishedContent content, IPublishedContent other)
{
return content.Id == other.Id;
}
public static HtmlString IsEqual(this IPublishedContent content, IPublishedContent other, string valueIfTrue)
{
return content.IsEqual(other, valueIfTrue, string.Empty);
}
public static HtmlString IsEqual(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsEqual(other) ? valueIfTrue : valueIfFalse);
}
public static bool IsNotEqual(this IPublishedContent content, IPublishedContent other)
{
return content.IsEqual(other) == false;
}
public static HtmlString IsNotEqual(this IPublishedContent content, IPublishedContent other, string valueIfTrue)
{
return content.IsNotEqual(other, valueIfTrue, string.Empty);
}
public static HtmlString IsNotEqual(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsNotEqual(other) ? valueIfTrue : valueIfFalse);
}
#endregion
#region IsSomething: ancestors and descendants
public static bool IsDescendant(this IPublishedContent content, IPublishedContent other)
{
Merge remote-tracking branch 'origin/dev-v7' into temp8 # Conflicts: # build/NuSpecs/tools/Web.config.install.xdt # src/Umbraco.Core/Constants-Conventions.cs # src/Umbraco.Core/DatabaseContext.cs # src/Umbraco.Core/Models/Rdbms/LanguageDto.cs # src/Umbraco.Core/Models/Rdbms/RelationTypeDto.cs # src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs # src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs # src/Umbraco.Core/PropertyEditors/PreValueField.cs # src/Umbraco.Core/PropertyEditors/SupportTagsAttribute.cs # src/Umbraco.Core/Services/FileService.cs # src/Umbraco.Core/Services/IFileService.cs # src/Umbraco.Core/Strategies/RelateOnTrashHandler.cs # src/Umbraco.Tests/App.config # src/Umbraco.Tests/Persistence/Repositories/RelationTypeRepositoryTest.cs # src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs # src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js # src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js # src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js # src/Umbraco.Web.UI.Client/src/less/belle.less # src/Umbraco.Web.UI.Client/src/less/components/application/umb-drawer.less # src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less # src/Umbraco.Web.UI.Client/src/less/hacks.less # src/Umbraco.Web.UI.Client/src/less/property-editors.less # src/Umbraco.Web.UI.Client/src/less/variables.less # src/Umbraco.Web.UI.Client/src/views/common/dialogs/insertmacro.controller.js # src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.html # src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html # src/Umbraco.Web.UI.Client/src/views/components/umb-grid-selector.html # src/Umbraco.Web.UI.Client/src/views/datatypes/datatype.edit.controller.js # src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.html # src/Umbraco.Web.UI.Client/src/views/media/move.html # src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html # src/Umbraco.Web.UI/Views/Web.config # src/Umbraco.Web.UI/umbraco/Install/Views/Web.config # src/Umbraco.Web.UI/umbraco/config/lang/da.xml # src/Umbraco.Web.UI/umbraco/config/lang/en.xml # src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/umbraco/config/lang/nl.xml # src/Umbraco.Web.UI/umbraco/config/lang/ru.xml # src/Umbraco.Web.UI/web.Template.Debug.config # src/Umbraco.Web.UI/web.Template.config # src/Umbraco.Web/Editors/TemplateController.cs # src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs # src/Umbraco.Web/Models/ContentEditing/PreValueFieldDisplay.cs # src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs # src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs # src/Umbraco.Web/PropertyEditors/ValueListPreValueEditor.cs # src/Umbraco.Web/PublishedContentExtensions.cs # src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs # src/Umbraco.Web/Trees/MediaTreeController.cs # src/umbraco.MacroEngines/Resources/Web.config # src/umbraco.cms/Actions/ActionRestore.cs # src/umbraco.editorControls/yesno/YesNoDataType.cs
2018-07-30 21:31:35 +10:00
return other.Level < content.Level && content.Path.InvariantStartsWith(other.Path.EnsureEndsWith(','));
2018-06-29 19:52:40 +02:00
}
public static HtmlString IsDescendant(this IPublishedContent content, IPublishedContent other, string valueIfTrue)
{
return content.IsDescendant(other, valueIfTrue, string.Empty);
}
public static HtmlString IsDescendant(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsDescendant(other) ? valueIfTrue : valueIfFalse);
}
public static bool IsDescendantOrSelf(this IPublishedContent content, IPublishedContent other)
{
Merge remote-tracking branch 'origin/dev-v7' into temp8 # Conflicts: # build/NuSpecs/tools/Web.config.install.xdt # src/Umbraco.Core/Constants-Conventions.cs # src/Umbraco.Core/DatabaseContext.cs # src/Umbraco.Core/Models/Rdbms/LanguageDto.cs # src/Umbraco.Core/Models/Rdbms/RelationTypeDto.cs # src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs # src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs # src/Umbraco.Core/PropertyEditors/PreValueField.cs # src/Umbraco.Core/PropertyEditors/SupportTagsAttribute.cs # src/Umbraco.Core/Services/FileService.cs # src/Umbraco.Core/Services/IFileService.cs # src/Umbraco.Core/Strategies/RelateOnTrashHandler.cs # src/Umbraco.Tests/App.config # src/Umbraco.Tests/Persistence/Repositories/RelationTypeRepositoryTest.cs # src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs # src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js # src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js # src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js # src/Umbraco.Web.UI.Client/src/less/belle.less # src/Umbraco.Web.UI.Client/src/less/components/application/umb-drawer.less # src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less # src/Umbraco.Web.UI.Client/src/less/hacks.less # src/Umbraco.Web.UI.Client/src/less/property-editors.less # src/Umbraco.Web.UI.Client/src/less/variables.less # src/Umbraco.Web.UI.Client/src/views/common/dialogs/insertmacro.controller.js # src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.html # src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html # src/Umbraco.Web.UI.Client/src/views/components/umb-grid-selector.html # src/Umbraco.Web.UI.Client/src/views/datatypes/datatype.edit.controller.js # src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.html # src/Umbraco.Web.UI.Client/src/views/media/move.html # src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html # src/Umbraco.Web.UI/Views/Web.config # src/Umbraco.Web.UI/umbraco/Install/Views/Web.config # src/Umbraco.Web.UI/umbraco/config/lang/da.xml # src/Umbraco.Web.UI/umbraco/config/lang/en.xml # src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/umbraco/config/lang/nl.xml # src/Umbraco.Web.UI/umbraco/config/lang/ru.xml # src/Umbraco.Web.UI/web.Template.Debug.config # src/Umbraco.Web.UI/web.Template.config # src/Umbraco.Web/Editors/TemplateController.cs # src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs # src/Umbraco.Web/Models/ContentEditing/PreValueFieldDisplay.cs # src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs # src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs # src/Umbraco.Web/PropertyEditors/ValueListPreValueEditor.cs # src/Umbraco.Web/PublishedContentExtensions.cs # src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs # src/Umbraco.Web/Trees/MediaTreeController.cs # src/umbraco.MacroEngines/Resources/Web.config # src/umbraco.cms/Actions/ActionRestore.cs # src/umbraco.editorControls/yesno/YesNoDataType.cs
2018-07-30 21:31:35 +10:00
return content.Path.InvariantEquals(other.Path) || content.IsDescendant(other);
2018-06-29 19:52:40 +02:00
}
public static HtmlString IsDescendantOrSelf(this IPublishedContent content, IPublishedContent other, string valueIfTrue)
{
return content.IsDescendantOrSelf(other, valueIfTrue, string.Empty);
}
public static HtmlString IsDescendantOrSelf(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsDescendantOrSelf(other) ? valueIfTrue : valueIfFalse);
}
public static bool IsAncestor(this IPublishedContent content, IPublishedContent other)
{
Merge remote-tracking branch 'origin/dev-v7' into temp8 # Conflicts: # build/NuSpecs/tools/Web.config.install.xdt # src/Umbraco.Core/Constants-Conventions.cs # src/Umbraco.Core/DatabaseContext.cs # src/Umbraco.Core/Models/Rdbms/LanguageDto.cs # src/Umbraco.Core/Models/Rdbms/RelationTypeDto.cs # src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs # src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs # src/Umbraco.Core/PropertyEditors/PreValueField.cs # src/Umbraco.Core/PropertyEditors/SupportTagsAttribute.cs # src/Umbraco.Core/Services/FileService.cs # src/Umbraco.Core/Services/IFileService.cs # src/Umbraco.Core/Strategies/RelateOnTrashHandler.cs # src/Umbraco.Tests/App.config # src/Umbraco.Tests/Persistence/Repositories/RelationTypeRepositoryTest.cs # src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs # src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js # src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js # src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js # src/Umbraco.Web.UI.Client/src/less/belle.less # src/Umbraco.Web.UI.Client/src/less/components/application/umb-drawer.less # src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less # src/Umbraco.Web.UI.Client/src/less/hacks.less # src/Umbraco.Web.UI.Client/src/less/property-editors.less # src/Umbraco.Web.UI.Client/src/less/variables.less # src/Umbraco.Web.UI.Client/src/views/common/dialogs/insertmacro.controller.js # src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.html # src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html # src/Umbraco.Web.UI.Client/src/views/components/umb-grid-selector.html # src/Umbraco.Web.UI.Client/src/views/datatypes/datatype.edit.controller.js # src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.html # src/Umbraco.Web.UI.Client/src/views/media/move.html # src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html # src/Umbraco.Web.UI/Views/Web.config # src/Umbraco.Web.UI/umbraco/Install/Views/Web.config # src/Umbraco.Web.UI/umbraco/config/lang/da.xml # src/Umbraco.Web.UI/umbraco/config/lang/en.xml # src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/umbraco/config/lang/nl.xml # src/Umbraco.Web.UI/umbraco/config/lang/ru.xml # src/Umbraco.Web.UI/web.Template.Debug.config # src/Umbraco.Web.UI/web.Template.config # src/Umbraco.Web/Editors/TemplateController.cs # src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs # src/Umbraco.Web/Models/ContentEditing/PreValueFieldDisplay.cs # src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs # src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs # src/Umbraco.Web/PropertyEditors/ValueListPreValueEditor.cs # src/Umbraco.Web/PublishedContentExtensions.cs # src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs # src/Umbraco.Web/Trees/MediaTreeController.cs # src/umbraco.MacroEngines/Resources/Web.config # src/umbraco.cms/Actions/ActionRestore.cs # src/umbraco.editorControls/yesno/YesNoDataType.cs
2018-07-30 21:31:35 +10:00
return content.Level < other.Level && other.Path.InvariantStartsWith(content.Path.EnsureEndsWith(','));
2018-06-29 19:52:40 +02:00
}
public static HtmlString IsAncestor(this IPublishedContent content, IPublishedContent other, string valueIfTrue)
{
return content.IsAncestor(other, valueIfTrue, string.Empty);
}
public static HtmlString IsAncestor(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsAncestor(other) ? valueIfTrue : valueIfFalse);
}
public static bool IsAncestorOrSelf(this IPublishedContent content, IPublishedContent other)
{
Merge remote-tracking branch 'origin/dev-v7' into temp8 # Conflicts: # build/NuSpecs/tools/Web.config.install.xdt # src/Umbraco.Core/Constants-Conventions.cs # src/Umbraco.Core/DatabaseContext.cs # src/Umbraco.Core/Models/Rdbms/LanguageDto.cs # src/Umbraco.Core/Models/Rdbms/RelationTypeDto.cs # src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs # src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs # src/Umbraco.Core/PropertyEditors/PreValueField.cs # src/Umbraco.Core/PropertyEditors/SupportTagsAttribute.cs # src/Umbraco.Core/Services/FileService.cs # src/Umbraco.Core/Services/IFileService.cs # src/Umbraco.Core/Strategies/RelateOnTrashHandler.cs # src/Umbraco.Tests/App.config # src/Umbraco.Tests/Persistence/Repositories/RelationTypeRepositoryTest.cs # src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs # src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js # src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js # src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js # src/Umbraco.Web.UI.Client/src/less/belle.less # src/Umbraco.Web.UI.Client/src/less/components/application/umb-drawer.less # src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less # src/Umbraco.Web.UI.Client/src/less/hacks.less # src/Umbraco.Web.UI.Client/src/less/property-editors.less # src/Umbraco.Web.UI.Client/src/less/variables.less # src/Umbraco.Web.UI.Client/src/views/common/dialogs/insertmacro.controller.js # src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.html # src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html # src/Umbraco.Web.UI.Client/src/views/components/umb-grid-selector.html # src/Umbraco.Web.UI.Client/src/views/datatypes/datatype.edit.controller.js # src/Umbraco.Web.UI.Client/src/views/documenttypes/views/templates/templates.html # src/Umbraco.Web.UI.Client/src/views/media/move.html # src/Umbraco.Web.UI.Client/src/views/prevalueeditors/multivalues.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.prevalues.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html # src/Umbraco.Web.UI/Views/Web.config # src/Umbraco.Web.UI/umbraco/Install/Views/Web.config # src/Umbraco.Web.UI/umbraco/config/lang/da.xml # src/Umbraco.Web.UI/umbraco/config/lang/en.xml # src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/umbraco/config/lang/nl.xml # src/Umbraco.Web.UI/umbraco/config/lang/ru.xml # src/Umbraco.Web.UI/web.Template.Debug.config # src/Umbraco.Web.UI/web.Template.config # src/Umbraco.Web/Editors/TemplateController.cs # src/Umbraco.Web/Models/ContentEditing/ContentItemDisplay.cs # src/Umbraco.Web/Models/ContentEditing/PreValueFieldDisplay.cs # src/Umbraco.Web/PropertyEditors/ColorListPreValueEditor.cs # src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs # src/Umbraco.Web/PropertyEditors/ValueListPreValueEditor.cs # src/Umbraco.Web/PublishedContentExtensions.cs # src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs # src/Umbraco.Web/Trees/MediaTreeController.cs # src/umbraco.MacroEngines/Resources/Web.config # src/umbraco.cms/Actions/ActionRestore.cs # src/umbraco.editorControls/yesno/YesNoDataType.cs
2018-07-30 21:31:35 +10:00
return other.Path.InvariantEquals(content.Path) || content.IsAncestor(other);
2018-06-29 19:52:40 +02:00
}
public static HtmlString IsAncestorOrSelf(this IPublishedContent content, IPublishedContent other, string valueIfTrue)
{
return content.IsAncestorOrSelf(other, valueIfTrue, string.Empty);
}
public static HtmlString IsAncestorOrSelf(this IPublishedContent content, IPublishedContent other, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(content.IsAncestorOrSelf(other) ? valueIfTrue : valueIfFalse);
}
#endregion
#region Axes: descendants, descendants-or-self
/// <summary>
/// Returns all DescendantsOrSelf of all content referenced
/// </summary>
/// <param name="parentNodes"></param>
/// <param name="docTypeAlias"></param>
2019-01-16 08:21:24 +01:00
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
2018-06-29 19:52:40 +02:00
/// <returns></returns>
/// <remarks>
/// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
/// </remarks>
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(this IEnumerable<IPublishedContent> parentNodes, string docTypeAlias, string culture = null)
2018-06-29 19:52:40 +02:00
{
return parentNodes.DescendantsOrSelfOfType(VariationContextAccessor, docTypeAlias, culture);
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Returns all DescendantsOrSelf of all content referenced
/// </summary>
/// <param name="parentNodes"></param>
2019-01-16 08:21:24 +01:00
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
2018-06-29 19:52:40 +02:00
/// <returns></returns>
/// <remarks>
/// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
/// </remarks>
2019-01-16 08:21:24 +01:00
public static IEnumerable<T> DescendantsOrSelf<T>(this IEnumerable<IPublishedContent> parentNodes, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return parentNodes.DescendantsOrSelf<T>(VariationContextAccessor, culture);
2018-06-29 19:52:40 +02:00
}
2019-01-16 08:21:24 +01:00
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.Descendants(VariationContextAccessor, culture);
2018-06-29 19:52:40 +02:00
}
2019-01-16 08:21:24 +01:00
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, int level, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.Descendants(VariationContextAccessor, level, culture);
2018-06-29 19:52:40 +02:00
}
public static IEnumerable<IPublishedContent> DescendantsOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.DescendantsOfType(VariationContextAccessor, contentTypeAlias, culture);
2018-06-29 19:52:40 +02:00
}
2019-01-16 08:21:24 +01:00
public static IEnumerable<T> Descendants<T>(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.Descendants<T>(VariationContextAccessor, culture);
2018-06-29 19:52:40 +02:00
}
2019-01-16 08:21:24 +01:00
public static IEnumerable<T> Descendants<T>(this IPublishedContent content, int level, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.Descendants<T>(VariationContextAccessor, level, culture);
2018-06-29 19:52:40 +02:00
}
2019-01-16 08:21:24 +01:00
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.DescendantsOrSelf(VariationContextAccessor, culture);
2018-06-29 19:52:40 +02:00
}
2019-01-16 08:21:24 +01:00
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, int level, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.DescendantsOrSelf(VariationContextAccessor, level, culture);
2018-06-29 19:52:40 +02:00
}
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.DescendantsOrSelfOfType(VariationContextAccessor, contentTypeAlias, culture);
2018-06-29 19:52:40 +02:00
}
2019-01-16 08:21:24 +01:00
public static IEnumerable<T> DescendantsOrSelf<T>(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.DescendantsOrSelf<T>(VariationContextAccessor, culture);
2018-06-29 19:52:40 +02:00
}
2019-01-16 08:21:24 +01:00
public static IEnumerable<T> DescendantsOrSelf<T>(this IPublishedContent content, int level, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.DescendantsOrSelf<T>(VariationContextAccessor, level, culture);
2018-06-29 19:52:40 +02:00
}
public static IPublishedContent Descendant(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.Descendant(VariationContextAccessor, culture);
2018-06-29 19:52:40 +02:00
}
public static IPublishedContent Descendant(this IPublishedContent content, int level, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.Descendant(VariationContextAccessor, level, culture);
2018-06-29 19:52:40 +02:00
}
public static IPublishedContent DescendantOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.DescendantOfType(VariationContextAccessor, contentTypeAlias, culture);
2018-06-29 19:52:40 +02:00
}
public static T Descendant<T>(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.Descendant<T>(VariationContextAccessor, culture);
2018-06-29 19:52:40 +02:00
}
public static T Descendant<T>(this IPublishedContent content, int level, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.Descendant<T>(VariationContextAccessor, level, culture);
2018-06-29 19:52:40 +02:00
}
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, int level, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.DescendantOrSelf(VariationContextAccessor, level, culture);
2018-06-29 19:52:40 +02:00
}
public static IPublishedContent DescendantOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.DescendantOrSelfOfType(VariationContextAccessor, contentTypeAlias, culture);
2018-06-29 19:52:40 +02:00
}
public static T DescendantOrSelf<T>(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.DescendantOrSelf<T>(VariationContextAccessor, culture);
2018-06-29 19:52:40 +02:00
}
public static T DescendantOrSelf<T>(this IPublishedContent content, int level, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.DescendantOrSelf<T>(VariationContextAccessor, level, culture);
2018-06-29 19:52:40 +02:00
}
#endregion
#region Axes: children
/// <summary>
/// Gets the children of the content, filtered by a predicate.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="predicate">The predicate.</param>
2019-01-16 08:21:24 +01:00
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
2018-06-29 19:52:40 +02:00
/// <returns>The children of the content, filtered by the predicate.</returns>
/// <remarks>
/// <para>Children are sorted by their sortOrder.</para>
/// </remarks>
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, Func<IPublishedContent, bool> predicate, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.Children(VariationContextAccessor, culture).Where(predicate);
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets the children of the content, of any of the specified types.
/// </summary>
/// <param name="content">The content.</param>
2019-01-16 08:21:24 +01:00
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
/// <param name="contentTypeAlias">The content type alias.</param>
2018-06-29 19:52:40 +02:00
/// <returns>The children of the content, of any of the specified types.</returns>
public static IEnumerable<IPublishedContent> ChildrenOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.Children(VariationContextAccessor, x => x.ContentType.Alias.InvariantEquals(contentTypeAlias), culture);
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets the children of the content, of a given content type.
/// </summary>
/// <typeparam name="T">The content type.</typeparam>
/// <param name="content">The content.</param>
2019-01-16 08:21:24 +01:00
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
2018-06-29 19:52:40 +02:00
/// <returns>The children of content, of the given content type.</returns>
/// <remarks>
/// <para>Children are sorted by their sortOrder.</para>
/// </remarks>
public static IEnumerable<T> Children<T>(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.Children(VariationContextAccessor, culture).OfType<T>();
2018-06-29 19:52:40 +02:00
}
public static IPublishedContent FirstChild(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.Children(VariationContextAccessor, culture).FirstOrDefault();
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets the first child of the content, of a given content type.
/// </summary>
public static IPublishedContent FirstChildOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.ChildrenOfType(VariationContextAccessor, contentTypeAlias, culture).FirstOrDefault();
2018-06-29 19:52:40 +02:00
}
public static IPublishedContent FirstChild(this IPublishedContent content, Func<IPublishedContent, bool> predicate, string culture = null)
2018-06-29 19:52:40 +02:00
{
return content.Children(VariationContextAccessor, predicate, culture).FirstOrDefault();
2018-06-29 19:52:40 +02:00
}
public static IPublishedContent FirstChild(this IPublishedContent content, Guid uniqueId, string culture = null)
{
return content.Children(VariationContextAccessor, x => x.Key == uniqueId, culture).FirstOrDefault();
}
public static T FirstChild<T>(this IPublishedContent content, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.Children<T>(VariationContextAccessor, culture).FirstOrDefault();
2018-06-29 19:52:40 +02:00
}
public static T FirstChild<T>(this IPublishedContent content, Func<T, bool> predicate, string culture = null)
2018-06-29 19:52:40 +02:00
where T : class, IPublishedContent
{
return content.Children<T>(VariationContextAccessor, culture).FirstOrDefault(predicate);
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets the children of the content in a DataTable.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="services">A service context.</param>
/// <param name="contentTypeAliasFilter">An optional content type alias.</param>
2019-01-16 08:21:24 +01:00
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
2018-06-29 19:52:40 +02:00
/// <returns>The children of the content.</returns>
public static DataTable ChildrenAsTable(this IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "", string culture = null)
2018-06-29 19:52:40 +02:00
{
return GenerateDataTable(content, services, contentTypeAliasFilter, culture);
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets the children of the content in a DataTable.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="services">A service context.</param>
/// <param name="contentTypeAliasFilter">An optional content type alias.</param>
2019-01-16 08:21:24 +01:00
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
2018-06-29 19:52:40 +02:00
/// <returns>The children of the content.</returns>
private static DataTable GenerateDataTable(IPublishedContent content, ServiceContext services, string contentTypeAliasFilter = "", string culture = null)
2018-06-29 19:52:40 +02:00
{
var firstNode = contentTypeAliasFilter.IsNullOrWhiteSpace()
? content.Children(VariationContextAccessor, culture).Any()
? content.Children(VariationContextAccessor, culture).ElementAt(0)
2018-06-29 19:52:40 +02:00
: null
: content.Children(VariationContextAccessor, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAliasFilter));
2018-06-29 19:52:40 +02:00
if (firstNode == null)
return new DataTable(); //no children found
//use new utility class to create table so that we don't have to maintain code in many places, just one
var dt = Core.DataTableExtensions.GenerateDataTable(
//pass in the alias of the first child node since this is the node type we're rendering headers for
firstNode.ContentType.Alias,
//pass in the callback to extract the Dictionary<string, string> of all defined aliases to their names
alias => GetPropertyAliasesAndNames(services, alias),
//pass in a callback to populate the datatable, yup its a bit ugly but it's already legacy and we just want to maintain code in one place.
() =>
{
//create all row data
var tableData = Core.DataTableExtensions.CreateTableData();
//loop through each child and create row data for it
foreach (var n in content.Children(VariationContextAccessor).OrderBy(x => x.SortOrder))
2018-06-29 19:52:40 +02:00
{
if (contentTypeAliasFilter.IsNullOrWhiteSpace() == false)
{
if (n.ContentType.Alias.InvariantEquals(contentTypeAliasFilter) == false)
2018-06-29 19:52:40 +02:00
continue; //skip this one, it doesn't match the filter
}
var standardVals = new Dictionary<string, object>
{
{ "Id", n.Id },
{ "NodeName", n.Name(VariationContextAccessor) },
{ "NodeTypeAlias", n.ContentType.Alias },
{ "CreateDate", n.CreateDate },
{ "UpdateDate", n.UpdateDate },
{ "CreatorId", n.CreatorId},
{ "WriterId", n.WriterId },
{ "Url", n.Url() }
};
2018-06-29 19:52:40 +02:00
var userVals = new Dictionary<string, object>();
foreach (var p in from IPublishedProperty p in n.Properties where p.GetSourceValue() != null select p)
{
// probably want the "object value" of the property here...
userVals[p.Alias] = p.GetValue();
}
//add the row data
Core.DataTableExtensions.AddRowData(tableData, standardVals, userVals);
}
return tableData;
}
);
return dt;
}
#endregion
#region Axes: Siblings
2019-03-05 13:02:59 +01:00
/// <summary>
/// Gets the siblings of the content.
2019-03-05 13:02:59 +01:00
/// </summary>
/// <param name="content">The content.</param>
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
/// <returns>The siblings of the content.</returns>
/// <remarks>
/// <para>Note that in V7 this method also return the content node self.</para>
/// </remarks>
public static IEnumerable<IPublishedContent> Siblings(this IPublishedContent content, string culture = null)
{
return content.Siblings(PublishedSnapshot, VariationContextAccessor, culture);
}
/// <summary>
/// Gets the siblings of the content, of a given content type.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
/// <param name="contentTypeAlias">The content type alias.</param>
/// <returns>The siblings of the content, of the given content type.</returns>
/// <remarks>
/// <para>Note that in V7 this method also return the content node self.</para>
/// </remarks>
public static IEnumerable<IPublishedContent> SiblingsOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
return content.SiblingsOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, culture);
}
/// <summary>
/// Gets the siblings of the content, of a given content type.
/// </summary>
/// <typeparam name="T">The content type.</typeparam>
/// <param name="content">The content.</param>
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
/// <returns>The siblings of the content, of the given content type.</returns>
/// <remarks>
/// <para>Note that in V7 this method also return the content node self.</para>
/// </remarks>
public static IEnumerable<T> Siblings<T>(this IPublishedContent content, string culture = null)
where T : class, IPublishedContent
{
return content.Siblings<T>(PublishedSnapshot, VariationContextAccessor, culture);
}
/// <summary>
/// Gets the siblings of the content including the node itself to indicate the position.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
/// <returns>The siblings of the content including the node itself.</returns>
public static IEnumerable<IPublishedContent> SiblingsAndSelf(this IPublishedContent content, string culture = null)
2019-03-05 13:02:59 +01:00
{
return content.SiblingsAndSelf(PublishedSnapshot, VariationContextAccessor, culture);
2019-03-05 13:02:59 +01:00
}
/// <summary>
/// Gets the siblings of the content including the node itself to indicate the position, of a given content type.
2019-03-05 13:02:59 +01:00
/// </summary>
/// <param name="content">The content.</param>
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
/// <param name="contentTypeAlias">The content type alias.</param>
/// <returns>The siblings of the content including the node itself, of the given content type.</returns>
public static IEnumerable<IPublishedContent> SiblingsAndSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
2019-03-05 13:02:59 +01:00
{
return content.SiblingsAndSelfOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, culture);
2019-03-05 13:02:59 +01:00
}
/// <summary>
/// Gets the siblings of the content including the node itself to indicate the position, of a given content type.
2019-03-05 13:02:59 +01:00
/// </summary>
/// <typeparam name="T">The content type.</typeparam>
/// <param name="content">The content.</param>
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null)</param>
/// <returns>The siblings of the content including the node itself, of the given content type.</returns>
public static IEnumerable<T> SiblingsAndSelf<T>(this IPublishedContent content, string culture = null)
2019-03-05 13:02:59 +01:00
where T : class, IPublishedContent
{
return content.SiblingsAndSelf<T>(PublishedSnapshot, VariationContextAccessor, culture);
2018-06-29 19:52:40 +02:00
}
#endregion
#region PropertyAliasesAndNames
private static Func<ServiceContext, string, Dictionary<string, string>> _getPropertyAliasesAndNames;
/// <summary>
/// This is used only for unit tests to set the delegate to look up aliases/names dictionary of a content type
/// </summary>
internal static Func<ServiceContext, string, Dictionary<string, string>> GetPropertyAliasesAndNames
{
get => _getPropertyAliasesAndNames ?? GetAliasesAndNames;
set => _getPropertyAliasesAndNames = value;
}
private static Dictionary<string, string> GetAliasesAndNames(ServiceContext services, string alias)
{
var type = services.ContentTypeService.Get(alias)
?? services.MediaTypeService.Get(alias)
?? (IContentTypeBase)services.MemberTypeService.Get(alias);
var fields = GetAliasesAndNames(type);
// ensure the standard fields are there
var stdFields = new Dictionary<string, string>
{
{"Id", "Id"},
{"NodeName", "NodeName"},
{"NodeTypeAlias", "NodeTypeAlias"},
{"CreateDate", "CreateDate"},
{"UpdateDate", "UpdateDate"},
{"CreatorName", "CreatorName"},
{"WriterName", "WriterName"},
{"Url", "Url"}
};
foreach (var field in stdFields.Where(x => fields.ContainsKey(x.Key) == false))
{
fields[field.Key] = field.Value;
}
return fields;
}
private static Dictionary<string, string> GetAliasesAndNames(IContentTypeBase contentType)
{
return contentType.PropertyTypes.ToDictionary(x => x.Alias, x => x.Name);
}
#endregion
#region Url
/// <summary>
/// Gets the url of the content item.
/// </summary>
/// <remarks>
/// <para>If the content item is a document, then this method returns the url of the
/// document. If it is a media, then this methods return the media url for the
/// 'umbracoFile' property. Use the MediaUrl() method to get the media url for other
/// properties.</para>
/// <para>The value of this property is contextual. It depends on the 'current' request uri,
/// if any. In addition, when the content type is multi-lingual, this is the url for the
/// specified culture. Otherwise, it is the invariant url.</para>
/// </remarks>
public static string Url(this IPublishedContent content, string culture = null, UrlMode mode = UrlMode.Default)
{
var umbracoContext = Composing.Current.UmbracoContext;
if (umbracoContext == null)
throw new InvalidOperationException("Cannot resolve a Url when Current.UmbracoContext is null.");
if (umbracoContext.UrlProvider == null)
throw new InvalidOperationException("Cannot resolve a Url when Current.UmbracoContext.UrlProvider is null.");
switch (content.ContentType.ItemType)
{
case PublishedItemType.Content:
return umbracoContext.UrlProvider.GetUrl(content, mode, culture);
case PublishedItemType.Media:
return umbracoContext.UrlProvider.GetMediaUrl(content, mode, culture, Constants.Conventions.Media.File);
default:
throw new NotSupportedException();
}
}
#endregion
2018-06-29 19:52:40 +02:00
}
}