2017-07-20 11:21:28 +02:00
using System ;
2016-06-29 15:28:40 +02:00
using System.Collections.Generic ;
using System.Linq ;
using System.Web ;
using Umbraco.Core.Models.PublishedContent ;
namespace Umbraco.Web
{
/// <summary>
2017-09-25 08:59:32 +02:00
/// Provides extension methods for <c>IPublishedElement</c>.
2016-06-29 15:28:40 +02:00
/// </summary>
2017-09-25 08:59:32 +02:00
public static class PublishedElementExtensions
2016-06-29 15:28:40 +02:00
{
#region IsComposedOf
/// <summary>
/// Gets a value indicating whether the content is of a content type composed of the given alias
/// </summary>
/// <param name="content">The content.</param>
/// <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>
2017-09-25 08:59:32 +02:00
public static bool IsComposedOf ( this IPublishedElement content , string alias )
2016-06-29 15:28:40 +02:00
{
return content . ContentType . CompositionAliases . Contains ( alias ) ;
}
#endregion
#region HasProperty
/// <summary>
/// Gets a value indicating whether the content has a property identified by its alias.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
/// <returns>A value indicating whether the content has the property identified by the alias.</returns>
/// <remarks>The content may have a property, and that property may not have a value.</remarks>
2017-09-25 08:59:32 +02:00
public static bool HasProperty ( this IPublishedElement content , string alias )
2016-06-29 15:28:40 +02:00
{
return content . ContentType . GetPropertyType ( alias ) ! = null ;
}
#endregion
#region HasValue
/// <summary>
/// Gets a value indicating whether the content has a value for a property identified by its alias.
/// </summary>
/// <remarks>Returns true if <c>GetProperty(alias)</c> is not <c>null</c> and <c>GetProperty(alias).HasValue</c> is <c>true</c>.</remarks>
2018-04-21 09:57:28 +02:00
public static bool HasValue ( this IPublishedElement content , string alias , string culture = null , string segment = null )
2016-06-29 15:28:40 +02:00
{
var prop = content . GetProperty ( alias ) ;
2018-04-21 09:57:28 +02:00
return prop ! = null & & prop . HasValue ( culture , segment ) ;
2016-06-29 15:28:40 +02:00
}
/// <summary>
/// Returns one of two strings depending on 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="valueIfTrue">The value to return if the content has a value for the property.</param>
/// <param name="valueIfFalse">The value to return if the content has no value for the property.</param>
/// <returns>Either <paramref name="valueIfTrue"/> or <paramref name="valueIfFalse"/> depending on whether the content
/// has a value for the property identified by the alias.</returns>
2018-04-21 09:57:28 +02:00
public static IHtmlString IfHasValue ( this IPublishedElement content , string alias , string valueIfTrue , string valueIfFalse = null )
2016-06-29 15:28:40 +02:00
{
return content . HasValue ( alias )
? new HtmlString ( valueIfTrue )
: new HtmlString ( valueIfFalse ? ? string . Empty ) ;
}
#endregion
2016-06-30 19:35:25 +02:00
#region Value
2016-06-29 15:28:40 +02:00
/// <summary>
/// Gets the value of a content's property identified by its alias.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
2018-04-21 09:57:28 +02:00
/// <param name="culture">The variation language.</param>
2017-12-06 11:51:35 +01:00
/// <param name="segment">The variation segment.</param>
2016-06-29 15:28:40 +02:00
/// <returns>The value of the content's property identified by the alias.</returns>
/// <remarks>
/// <para>The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering content.</para>
/// <para>If no property with the specified alias exists, or if the property has no value, returns <c>null</c>.</para>
/// <para>If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
2018-04-21 09:57:28 +02:00
public static object Value ( this IPublishedElement content , string alias , string culture = null , string segment = null )
2016-06-29 15:28:40 +02:00
{
var property = content . GetProperty ( alias ) ;
2018-04-21 09:57:28 +02:00
return property ? . GetValue ( culture , segment ) ;
2016-06-29 15:28:40 +02:00
}
/// <summary>
/// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
/// <param name="defaultValue">The default value.</param>
2018-04-21 09:57:28 +02:00
/// <param name="culture">The variation language.</param>
2017-12-06 11:51:35 +01:00
/// <param name="segment">The variation segment.</param>
2016-06-29 15:28:40 +02:00
/// <returns>The value of the content's property identified by the alias, if it exists, otherwise a default value.</returns>
/// <remarks>
/// <para>The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering content.</para>
/// <para>If no property with the specified alias exists, or if the property has no value, returns <paramref name="defaultValue"/>.</para>
/// <para>If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
2018-04-21 09:57:28 +02:00
public static object Value ( this IPublishedElement content , string alias , string defaultValue , string culture = null , string segment = null ) // fixme - kill
2016-06-29 15:28:40 +02:00
{
var property = content . GetProperty ( alias ) ;
2018-04-21 09:57:28 +02:00
return property = = null | | property . HasValue ( culture , segment ) = = false ? defaultValue : property . GetValue ( culture , segment ) ;
2016-06-29 15:28:40 +02:00
}
/// <summary>
/// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
/// <param name="defaultValue">The default value.</param>
2017-12-06 11:51:35 +01:00
/// <param name="languageId">The variation language.</param>
/// <param name="segment">The variation segment.</param>
2016-06-29 15:28:40 +02:00
/// <returns>The value of the content's property identified by the alias, if it exists, otherwise a default value.</returns>
/// <remarks>
/// <para>The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering content.</para>
/// <para>If no property with the specified alias exists, or if the property has no value, returns <paramref name="defaultValue"/>.</para>
/// <para>If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
2018-04-21 09:57:28 +02:00
public static object Value ( this IPublishedElement content , string alias , object defaultValue , string culture = null , string segment = null )
2016-06-29 15:28:40 +02:00
{
var property = content . GetProperty ( alias ) ;
2018-04-21 09:57:28 +02:00
return property = = null | | property . HasValue ( culture , segment ) = = false ? defaultValue : property . GetValue ( culture , segment ) ;
2016-06-29 15:28:40 +02:00
}
#endregion
2016-06-30 19:35:25 +02:00
#region Value < T >
2016-06-29 15:28:40 +02:00
/// <summary>
/// Gets the value of a content's property identified by its alias, converted to a specified type.
/// </summary>
/// <typeparam name="T">The target property type.</typeparam>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
2018-04-21 09:57:28 +02:00
/// <param name="culture">The variation language.</param>
2017-12-06 11:51:35 +01:00
/// <param name="segment">The variation segment.</param>
2016-06-29 15:28:40 +02:00
/// <returns>The value of the content's property identified by the alias, converted to the specified type.</returns>
/// <remarks>
/// <para>The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering content.</para>
/// <para>If no property with the specified alias exists, or if the property has no value, or if it could not be converted, returns <c>default(T)</c>.</para>
/// <para>If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
2018-04-21 09:57:28 +02:00
public static T Value < T > ( this IPublishedElement content , string alias , string culture = null , string segment = null )
2016-06-29 15:28:40 +02:00
{
2018-04-21 09:57:28 +02:00
return content . Value ( alias , false , default ( T ) , culture , segment ) ;
2016-06-29 15:28:40 +02:00
}
/// <summary>
/// Gets the value of a content's property identified by its alias, converted to a specified type, if it exists, otherwise a default value.
/// </summary>
/// <typeparam name="T">The target property type.</typeparam>
/// <param name="content">The content.</param>
/// <param name="alias">The property alias.</param>
/// <param name="defaultValue">The default value.</param>
2018-04-21 09:57:28 +02:00
/// <param name="culture">The variation language.</param>
2017-12-06 11:51:35 +01:00
/// <param name="segment">The variation segment.</param>
2016-06-29 15:28:40 +02:00
/// <returns>The value of the content's property identified by the alias, converted to the specified type, if it exists, otherwise a default value.</returns>
/// <remarks>
/// <para>The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering content.</para>
/// <para>If no property with the specified alias exists, or if the property has no value, or if it could not be converted, returns <paramref name="defaultValue"/>.</para>
/// <para>If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
2018-04-21 09:57:28 +02:00
public static T Value < T > ( this IPublishedElement content , string alias , T defaultValue , string culture = null , string segment = null )
2016-06-29 15:28:40 +02:00
{
2018-04-21 09:57:28 +02:00
return content . Value ( alias , true , defaultValue , culture , segment ) ;
2016-06-29 15:28:40 +02:00
}
2018-04-21 09:57:28 +02:00
internal static T Value < T > ( this IPublishedElement content , string alias , bool withDefaultValue , T defaultValue , string culture = null , string segment = null ) // fixme uh?
2016-06-29 15:28:40 +02:00
{
var property = content . GetProperty ( alias ) ;
if ( property = = null ) return defaultValue ;
2018-04-21 09:57:28 +02:00
return property . Value ( withDefaultValue , defaultValue , culture , segment ) ;
2016-06-29 15:28:40 +02:00
}
#endregion
2017-12-06 11:51:35 +01:00
#region Value or Umbraco . Field - WORK IN PROGRESS
2016-06-30 19:35:25 +02:00
// trying to reproduce Umbraco.Field so we can get rid of it
//
// what we want:
// - alt aliases
// - recursion
// - default value
// - before & after (if value)
//
// convertLineBreaks: should be an extension string.ConvertLineBreaks()
// stripParagraphs: should be an extension string.StripParagraphs()
// format: should use the standard .ToString(format)
//
// see UmbracoComponentRenderer.Field - which is ugly ;-(
2016-06-30 20:25:40 +02:00
// recurse first, on each alias (that's how it's done in Field)
// TODO: strongly typed properties howto?
// there is no strongly typed recurse, etc => needs to be in ModelsBuilder?
2017-09-25 08:59:32 +02:00
public static IHtmlString Value < T > ( this IPublishedElement content , string aliases , Func < T , string > format , string alt = "" )
2016-06-30 20:25:40 +02:00
{
if ( format = = null ) format = x = > x . ToString ( ) ;
var property = aliases . Split ( ',' )
. Where ( x = > string . IsNullOrWhiteSpace ( x ) = = false )
. Select ( x = > content . GetProperty ( x . Trim ( ) ) )
. FirstOrDefault ( x = > x ! = null ) ;
return property ! = null
? new HtmlString ( format ( property . Value < T > ( ) ) )
: new HtmlString ( alt ) ;
}
// fixme - move that one!
public static IHtmlString Value < T > ( this IPublishedContent content , string aliases , Func < T , string > format , string alt = "" , bool recurse = false )
{
if ( format = = null ) format = x = > x . ToString ( ) ;
var property = aliases . Split ( ',' )
. Where ( x = > string . IsNullOrWhiteSpace ( x ) = = false )
. Select ( x = > content . GetProperty ( x . Trim ( ) , recurse ) )
. FirstOrDefault ( x = > x ! = null ) ;
return property ! = null
? new HtmlString ( format ( property . Value < T > ( ) ) )
: new HtmlString ( alt ) ;
}
2016-06-30 19:35:25 +02:00
#endregion
2016-06-29 15:28:40 +02:00
#region ToIndexedArray
public static IndexedArrayItem < TContent > [ ] ToIndexedArray < TContent > ( this IEnumerable < TContent > source )
2017-09-25 08:59:32 +02:00
where TContent : class , IPublishedElement
2016-06-29 15:28:40 +02:00
{
var set = source . Select ( ( content , index ) = > new IndexedArrayItem < TContent > ( content , index ) ) . ToArray ( ) ;
foreach ( var setItem in set ) setItem . TotalCount = set . Length ;
return set ;
}
#endregion
#region OfTypes
// the .OfType<T>() filter is nice when there's only one type
// this is to support filtering with multiple types
public static IEnumerable < T > OfTypes < T > ( this IEnumerable < T > contents , params string [ ] types )
2017-09-25 08:59:32 +02:00
where T : IPublishedElement
2016-06-29 15:28:40 +02:00
{
types = types . Select ( x = > x . ToLowerInvariant ( ) ) . ToArray ( ) ;
return contents . Where ( x = > types . Contains ( x . ContentType . Alias . ToLowerInvariant ( ) ) ) ;
}
#endregion
}
2017-07-20 11:21:28 +02:00
}