using System; using System.Collections.Generic; using System.Linq; using System.Web; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web { /// /// Provides extension methods for IPublishedElement. /// public static class PublishedElementExtensions { #region IsComposedOf /// /// Gets a value indicating whether the content is of a content type composed of the given alias /// /// The content. /// The content type alias. /// A value indicating whether the content is of a content type composed of a content type identified by the alias. public static bool IsComposedOf(this IPublishedElement content, string alias) { return content.ContentType.CompositionAliases.Contains(alias); } #endregion #region HasProperty /// /// Gets a value indicating whether the content has a property identified by its alias. /// /// The content. /// The property alias. /// A value indicating whether the content has the property identified by the alias. /// The content may have a property, and that property may not have a value. public static bool HasProperty(this IPublishedElement content, string alias) { return content.ContentType.GetPropertyType(alias) != null; } #endregion #region HasValue /// /// Gets a value indicating whether the content has a value for a property identified by its alias. /// /// Returns true if GetProperty(alias) is not null and GetProperty(alias).HasValue is true. public static bool HasValue(this IPublishedElement content, string alias, string culture = null, string segment = null) { var prop = content.GetProperty(alias); return prop != null && prop.HasValue(culture, segment); } /// /// Returns one of two strings depending on whether the content has a value for a property identified by its alias. /// /// The content. /// The property alias. /// The value to return if the content has a value for the property. /// The value to return if the content has no value for the property. /// Either or depending on whether the content /// has a value for the property identified by the alias. public static IHtmlString IfHasValue(this IPublishedElement content, string alias, string valueIfTrue, string valueIfFalse = null) { return content.HasValue(alias) ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse ?? string.Empty); } #endregion #region Value /// /// Gets the value of a content's property identified by its alias. /// /// The content. /// The property alias. /// The variation language. /// The variation segment. /// The value of the content's property identified by the alias. /// /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. /// If no property with the specified alias exists, or if the property has no value, returns null. /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. /// The alias is case-insensitive. /// public static object Value(this IPublishedElement content, string alias, string culture = null, string segment = null) { var property = content.GetProperty(alias); return property?.GetValue(culture, segment); } /// /// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value. /// /// The content. /// The property alias. /// The default value. /// The variation language. /// The variation segment. /// The value of the content's property identified by the alias, if it exists, otherwise a default value. /// /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. /// If no property with the specified alias exists, or if the property has no value, returns . /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. /// The alias is case-insensitive. /// public static object Value(this IPublishedElement content, string alias, string defaultValue, string culture = null, string segment = null) // fixme - kill { var property = content.GetProperty(alias); return property == null || property.HasValue(culture, segment) == false ? defaultValue : property.GetValue(culture, segment); } /// /// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value. /// /// The content. /// The property alias. /// The default value. /// The variation language. /// The variation segment. /// The value of the content's property identified by the alias, if it exists, otherwise a default value. /// /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. /// If no property with the specified alias exists, or if the property has no value, returns . /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. /// The alias is case-insensitive. /// public static object Value(this IPublishedElement content, string alias, object defaultValue, string culture = null, string segment = null) { var property = content.GetProperty(alias); return property == null || property.HasValue(culture, segment) == false ? defaultValue : property.GetValue(culture, segment); } #endregion #region Value /// /// Gets the value of a content's property identified by its alias, converted to a specified type. /// /// The target property type. /// The content. /// The property alias. /// The variation language. /// The variation segment. /// The value of the content's property identified by the alias, converted to the specified type. /// /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. /// If no property with the specified alias exists, or if the property has no value, or if it could not be converted, returns default(T). /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. /// The alias is case-insensitive. /// public static T Value(this IPublishedElement content, string alias, string culture = null, string segment = null) { return content.Value(alias, false, default(T), culture, segment); } /// /// Gets the value of a content's property identified by its alias, converted to a specified type, if it exists, otherwise a default value. /// /// The target property type. /// The content. /// The property alias. /// The default value. /// The variation language. /// The variation segment. /// The value of the content's property identified by the alias, converted to the specified type, if it exists, otherwise a default value. /// /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. /// If no property with the specified alias exists, or if the property has no value, or if it could not be converted, returns . /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. /// The alias is case-insensitive. /// public static T Value(this IPublishedElement content, string alias, T defaultValue, string culture = null, string segment = null) { return content.Value(alias, true, defaultValue, culture, segment); } internal static T Value(this IPublishedElement content, string alias, bool withDefaultValue, T defaultValue, string culture = null, string segment = null) // fixme uh? { var property = content.GetProperty(alias); if (property == null) return defaultValue; return property.Value(withDefaultValue, defaultValue, culture, segment); } #endregion #region Value or Umbraco.Field - WORK IN PROGRESS // 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 ;-( // 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? public static IHtmlString Value(this IPublishedElement content, string aliases, Func format, string alt = "") { 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())) : new HtmlString(alt); } // fixme - move that one! public static IHtmlString Value(this IPublishedContent content, string aliases, Func 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())) : new HtmlString(alt); } #endregion #region ToIndexedArray public static IndexedArrayItem[] ToIndexedArray(this IEnumerable source) where TContent : class, IPublishedElement { var set = source.Select((content, index) => new IndexedArrayItem(content, index)).ToArray(); foreach (var setItem in set) setItem.TotalCount = set.Length; return set; } #endregion #region OfTypes // the .OfType() filter is nice when there's only one type // this is to support filtering with multiple types public static IEnumerable OfTypes(this IEnumerable contents, params string[] types) where T : IPublishedElement { types = types.Select(x => x.ToLowerInvariant()).ToArray(); return contents.Where(x => types.Contains(x.ContentType.Alias.ToLowerInvariant())); } #endregion } }