public async Task <IHtmlContent> TabContainer(IDisplayHelper displayAsync, GroupingsViewModel shape, IShapeFactory shapeFactory) { var localNavigation = await shapeFactory.CreateAsync("LocalNavigation", Arguments.From(new { shape.Identifier, Tabs = shape.Groupings })); var htmlContentBuilder = new HtmlContentBuilder(); htmlContentBuilder.AppendHtml(await displayAsync.ShapeExecuteAsync(localNavigation)); var tagBuilder = shape.GetTagBuilder("div"); tagBuilder.AddCssClass("tab-content"); htmlContentBuilder.AppendHtml(tagBuilder); var first = true; foreach (var tab in shape.Items.OfType <IShape>()) { if (first) { first = false; tab.Classes.Add("show active"); } tagBuilder.InnerHtml.AppendHtml(await displayAsync.ShapeExecuteAsync(tab)); } return(htmlContentBuilder); }
protected async Task <bool> SendEmailAsync(string email, string subject, IShape model) { var body = string.Empty; using (var sb = StringBuilderPool.GetInstance()) { using (var sw = new StringWriter(sb.Builder)) { var htmlContent = await _displayHelper.ShapeExecuteAsync(model); htmlContent.WriteTo(sw, HtmlEncoder.Default); body = sw.ToString(); } } var message = new MailMessage() { To = email, Subject = subject, Body = body, IsBodyHtml = true }; var result = await _smtpService.SendAsync(message); return(result.Succeeded); }
public Task <IHtmlContent> LocalNavigation(IDisplayHelper displayAsync, IShape shape) { // Morphing this shape to keep Model untouched. shape.Metadata.Alternates.Clear(); shape.Metadata.Type = "AdminTabs"; return(displayAsync.ShapeExecuteAsync(shape)); }
public async Task <IHtmlContent> Zone(IDisplayHelper DisplayAsync, IEnumerable <object> Shape) { var htmlContentBuilder = new HtmlContentBuilder(); foreach (var item in Shape) { htmlContentBuilder.AppendHtml(await DisplayAsync.ShapeExecuteAsync((IShape)item)); } return(htmlContentBuilder); }
public async Task <IHtmlContent> Card(IDisplayHelper displayAsync, GroupingViewModel shape) { var tagBuilder = shape.GetTagBuilder("div"); tagBuilder.AddCssClass("card-body"); shape.Metadata.Alternates.Clear(); shape.Metadata.Type = "ColumnGrouping"; tagBuilder.InnerHtml.AppendHtml(await displayAsync.ShapeExecuteAsync(shape)); var cardIdPrefix = $"card-{shape.Identifier}-{shape.Grouping.Key}".HtmlClassify(); var cardTag = new TagBuilder("div"); cardTag.AddCssClass("card mb-2"); var headerArrowTag = new TagBuilder("div"); headerArrowTag.AddCssClass("card-header"); headerArrowTag.Attributes["id"] = $"heading-{cardIdPrefix}"; var headerTitleTag = new TagBuilder("h5"); headerTitleTag.AddCssClass("float-start mb-0 mt-1"); headerTitleTag.InnerHtml.Append(shape.Grouping.Key); var buttonTag = new TagBuilder("button"); buttonTag.AddCssClass("btn btn-link btn-block text-start float-end"); buttonTag.Attributes["type"] = "button"; buttonTag.Attributes["data-bs-toggle"] = "collapse"; buttonTag.Attributes["data-bs-target"] = $"#collapse-{cardIdPrefix}"; buttonTag.Attributes["aria-expanded"] = "true"; buttonTag.Attributes["aria-controls"] = $"collapse-{cardIdPrefix}"; var buttonIconTag = new TagBuilder("i"); buttonIconTag.AddCssClass("fa-solid fa-angle-down"); buttonTag.InnerHtml.AppendHtml(buttonIconTag); headerArrowTag.InnerHtml.AppendHtml(headerTitleTag); headerArrowTag.InnerHtml.AppendHtml(buttonTag); var bodyTag = new TagBuilder("div"); bodyTag.AddCssClass("collapse show"); bodyTag.Attributes["id"] = $"collapse-{cardIdPrefix}"; bodyTag.InnerHtml.AppendHtml(tagBuilder); cardTag.InnerHtml.AppendHtml(headerArrowTag); cardTag.InnerHtml.AppendHtml(bodyTag); return(cardTag); }
public async Task <IHtmlContent> Column(IDisplayHelper displayAsync, GroupViewModel shape) { var tagBuilder = shape.GetTagBuilder("div"); foreach (var column in shape.Items) { tagBuilder.InnerHtml.AppendHtml(await displayAsync.ShapeExecuteAsync((IShape)column)); } return(tagBuilder); }
public async Task <IHtmlContent> CardContainer(IDisplayHelper displayAsync, GroupViewModel shape) { var tagBuilder = shape.GetTagBuilder("div"); tagBuilder.AddCssClass("mb-3"); foreach (var card in shape.Items.OfType <IShape>()) { tagBuilder.InnerHtml.AppendHtml(await displayAsync.ShapeExecuteAsync(card)); } return(tagBuilder); }
public async Task <IHtmlContent> Tab(IDisplayHelper displayAsync, GroupingViewModel shape) { var tagBuilder = shape.GetTagBuilder("div"); tagBuilder.Attributes["id"] = $"tab-{shape.Grouping.Key}-{shape.Identifier}".HtmlClassify(); tagBuilder.AddCssClass("tab-pane fade"); // Morphing this shape to a grouping shape to keep Model untouched. shape.Metadata.Alternates.Clear(); shape.Metadata.Type = "CardGrouping"; tagBuilder.InnerHtml.AppendHtml(await displayAsync.ShapeExecuteAsync(shape)); return(tagBuilder); }
public async Task <IHtmlContent> ContentZone(IDisplayHelper DisplayAsync, dynamic Shape, IShapeFactory ShapeFactory) { var htmlContentBuilder = new HtmlContentBuilder(); // This maybe a collection of IShape, IHtmlContent, or plain object. var shapes = ((IEnumerable <object>)Shape); // Evaluate shapes for grouping metadata, when it is not an IShape it cannot be grouped. var isGrouped = shapes.Any(x => x is IShape s && (!String.IsNullOrEmpty(s.Metadata.Tab) || !String.IsNullOrEmpty(s.Metadata.Card) || !String.IsNullOrEmpty(s.Metadata.Column))); // When there is no grouping metadata on any shapes just render the Zone. if (!isGrouped) { foreach (var item in shapes) { htmlContentBuilder.AppendHtml(await DisplayAsync.ShapeExecuteAsync((IShape)item)); } return(htmlContentBuilder); } string identifier = Shape.Identifier ?? String.Empty; var groupings = shapes.ToLookup(x => { if (x is IShape s) { var key = s.Metadata.Tab; if (String.IsNullOrEmpty(key)) { return(ContentKey); } // Remove any positioning modifier. var modifierIndex = key.IndexOf(';'); if (modifierIndex != -1) { key = key.Substring(0, modifierIndex); } return(key); } return(ContentKey); }); // Process Tabs first, then Cards, then Columns. if (groupings.Count > 1) { var orderedGroupings = groupings.OrderBy(grouping => { var firstGroupWithModifier = grouping.FirstOrDefault(group => { if (group is IShape s && !String.IsNullOrEmpty(s.Metadata.Tab) && s.Metadata.Tab.IndexOf(';') != -1) { return(true); } return(false); }); if (firstGroupWithModifier is IShape shape) { var key = shape.Metadata.Tab; var modifierIndex = key.IndexOf(';'); return(new PositionalGrouping(key.Substring(modifierIndex))); } return(new PositionalGrouping(null)); }, FlatPositionComparer.Instance).ToArray(); var container = (GroupingsViewModel)await ShapeFactory.CreateAsync <GroupingsViewModel>("TabContainer", m => { m.Identifier = identifier; m.Groupings = orderedGroupings; }); container.Classes.Add("accordion"); foreach (var orderedGrouping in orderedGroupings) { var groupingShape = (GroupingViewModel)await ShapeFactory.CreateAsync <GroupingViewModel>("Tab", m => { m.Identifier = identifier; m.Grouping = orderedGrouping; }); foreach (var item in orderedGrouping) { await groupingShape.AddAsync(item); } await container.AddAsync(groupingShape); } htmlContentBuilder.AppendHtml(await DisplayAsync.ShapeExecuteAsync(container)); } else if (groupings.Count == 1) { // Evaluate for cards. var cardGrouping = (GroupingViewModel)await ShapeFactory.CreateAsync <GroupingViewModel>("CardGrouping", m => { m.Identifier = identifier; m.Grouping = groupings.ElementAt(0); }); htmlContentBuilder.AppendHtml(await DisplayAsync.ShapeExecuteAsync(cardGrouping)); } return(htmlContentBuilder); }
public async Task <IHtmlContent> ColumnGrouping(IDisplayHelper DisplayAsync, GroupingViewModel Shape, IShapeFactory ShapeFactory) { var htmlContentBuilder = new HtmlContentBuilder(); var groupings = Shape.Grouping.ToLookup(x => { if (x is IShape s) { var key = s.Metadata.Column; if (String.IsNullOrEmpty(key)) { return(ContentKey); } // Remove column modifier. var modifierIndex = key.IndexOf('_'); if (modifierIndex != -1) { key = key.Substring(0, modifierIndex); } // Remove positional modifier. modifierIndex = key.IndexOf(';'); if (modifierIndex != -1) { key = key.Substring(0, modifierIndex); } return(key); } return(ContentKey); }); if (groupings.Count > 1) { var positionModifiers = GetColumnPositions(groupings); var orderedGroupings = groupings.OrderBy(grouping => { if (positionModifiers.TryGetValue(grouping.Key, out var position)) { return(new PositionalGrouping { Position = position }); } else { return(new PositionalGrouping()); } }, FlatPositionComparer.Instance); var columnModifiers = GetColumnModifiers(orderedGroupings); var container = (GroupViewModel)await ShapeFactory.CreateAsync <GroupViewModel>("ColumnContainer", m => { m.Identifier = Shape.Identifier; }); foreach (var orderedGrouping in orderedGroupings) { var groupingShape = (GroupingViewModel)await ShapeFactory.CreateAsync <GroupingViewModel>("Column", m => { m.Identifier = Shape.Identifier; m.Grouping = orderedGrouping; }); groupingShape.Classes.Add("ta-col-grouping"); groupingShape.Classes.Add("column-" + orderedGrouping.Key.HtmlClassify()); // To adjust this breakpoint apply a modifier of lg-3 to every column. var columnClasses = "col-12 col-md"; if (columnModifiers.TryGetValue(orderedGrouping.Key, out var columnModifier)) { // When the modifier also has a - assume it is providing a breakpointed class. if (columnModifier.IndexOf('-') != -1) { columnClasses = "col-12 col-" + columnModifier; } else // Otherwise assume a default md breakpoint. { columnClasses = "col-12 col-md-" + columnModifier; } } groupingShape.Classes.Add(columnClasses); foreach (var item in orderedGrouping) { await groupingShape.AddAsync(item); } await container.AddAsync(groupingShape); } htmlContentBuilder.AppendHtml(await DisplayAsync.ShapeExecuteAsync(container)); } else { // When nothing is grouped in a column, the grouping is rendered directly. foreach (var item in Shape.Grouping) { htmlContentBuilder.AppendHtml(await DisplayAsync.ShapeExecuteAsync((IShape)item)); } } return(htmlContentBuilder); }
public async Task <IHtmlContent> CardGrouping(IDisplayHelper DisplayAsync, GroupingViewModel Shape, IShapeFactory ShapeFactory) { var htmlContentBuilder = new HtmlContentBuilder(); var groupings = Shape.Grouping.ToLookup(x => { if (x is IShape s) { var key = s.Metadata.Card; if (String.IsNullOrEmpty(key)) { return(ContentKey); } // Remove positional modifier. var modifierIndex = key.IndexOf(';'); if (modifierIndex != -1) { key = key.Substring(0, modifierIndex); } return(key); } return(ContentKey); }); if (groupings.Count > 1) { var orderedGroupings = groupings.OrderBy(grouping => { var firstGroupWithModifier = grouping.FirstOrDefault(group => { if (group is IShape s && !String.IsNullOrEmpty(s.Metadata.Card) && s.Metadata.Card.IndexOf(';') != -1) { return(true); } return(false); }); if (firstGroupWithModifier is IShape shape) { var key = shape.Metadata.Card; var modifierIndex = key.IndexOf(';'); return(new PositionalGrouping(key.Substring(modifierIndex))); } return(new PositionalGrouping()); }, FlatPositionComparer.Instance); var container = (GroupViewModel)await ShapeFactory.CreateAsync <GroupViewModel>("CardContainer", m => { m.Identifier = Shape.Identifier; }); container.Classes.Add("accordion"); foreach (var orderedGrouping in orderedGroupings) { var groupingShape = (GroupingViewModel)await ShapeFactory.CreateAsync <GroupingViewModel>("Card", m => { m.Identifier = Shape.Identifier; m.Grouping = orderedGrouping; }); foreach (var item in orderedGrouping) { await groupingShape.AddAsync(item); } await container.AddAsync(groupingShape); } htmlContentBuilder.AppendHtml(await DisplayAsync.ShapeExecuteAsync(container)); } else { // Evaluate for columns. var groupingShape = (GroupingViewModel)await ShapeFactory.CreateAsync <GroupingViewModel>("ColumnGrouping", m => { m.Identifier = Shape.Identifier; m.Grouping = Shape.Grouping; }); htmlContentBuilder.AppendHtml(await DisplayAsync.ShapeExecuteAsync(groupingShape)); } return(htmlContentBuilder); }
public override async Task ProcessAsync(TagHelperContext tagHelperContext, TagHelperOutput output) { // Extract all attributes from the tag helper to var properties = output.Attributes .Where(x => !InternalProperties.Contains(x.Name)) .ToDictionary(x => LowerKebabToPascalCase(x.Name), x => (object)x.Value.ToString()) ; if (string.IsNullOrWhiteSpace(Type)) { Type = output.TagName; } if (string.IsNullOrWhiteSpace(Cache) && output.Attributes.ContainsName("cache-id")) { Cache = Convert.ToString(output.Attributes["cache-id"].Value); } if (string.IsNullOrWhiteSpace(Context) && output.Attributes.ContainsName("cache-context")) { Context = Convert.ToString(output.Attributes["cache-context"].Value); } if (string.IsNullOrWhiteSpace(Tag) && output.Attributes.ContainsName("cache-tag")) { Tag = Convert.ToString(output.Attributes["cache-tag"].Value); } if (!FixedDuration.HasValue && output.Attributes.ContainsName("cache-fixed-duration")) { TimeSpan timespan; if (TimeSpan.TryParse(Convert.ToString(output.Attributes["cache-fixed-duration"].Value), out timespan)) { FixedDuration = timespan; } } if (!SlidingDuration.HasValue && output.Attributes.ContainsName("cache-sliding-duration")) { TimeSpan timespan; if (TimeSpan.TryParse(Convert.ToString(output.Attributes["cache-sliding-duration"].Value), out timespan)) { SlidingDuration = timespan; } } var shape = await _shapeFactory.CreateAsync(Type, Arguments.From(properties)); if (output.Attributes.ContainsName("id")) { shape.Id = Convert.ToString(output.Attributes["id"].Value); } if (output.Attributes.ContainsName("alternate")) { shape.Metadata.Alternates.Add(Convert.ToString(output.Attributes["alternate"].Value)); } if (output.Attributes.ContainsName("wrapper")) { shape.Metadata.Wrappers.Add(Convert.ToString(output.Attributes["wrapper"].Value)); } tagHelperContext.Items.Add(typeof(IShape), shape); if (!string.IsNullOrWhiteSpace(Cache)) { var metadata = shape.Metadata; metadata.Cache(Cache); if (FixedDuration.HasValue) { metadata.Cache().WithExpiryAfter(FixedDuration.Value); } if (SlidingDuration.HasValue) { metadata.Cache().WithExpirySliding(SlidingDuration.Value); } if (!string.IsNullOrWhiteSpace(Context)) { var contexts = Context.Split(Separators, StringSplitOptions.RemoveEmptyEntries); metadata.Cache().AddContext(contexts); } if (!string.IsNullOrWhiteSpace(Tag)) { var tags = Tag.Split(Separators, StringSplitOptions.RemoveEmptyEntries); metadata.Cache().AddTag(tags); } } await output.GetChildContentAsync(); output.Content.SetHtmlContent(await _displayHelper.ShapeExecuteAsync(shape)); // We don't want any encapsulating tag around the shape output.TagName = null; }
/// <summary> /// Renders a shape. /// </summary> /// <param name="shape">The shape.</param> public Task <IHtmlContent> DisplayAsync(dynamic shape) { EnsureDisplayHelper(); return(_displayHelper.ShapeExecuteAsync(shape)); }
public override async Task ProcessAsync(TagHelperContext tagHelperContext, TagHelperOutput output) { var properties = new Dictionary <string, object>(); // These prefixed properties are bound with their original type and not converted as IHtmlContent foreach (var property in Properties) { var normalizedName = property.Key.ToPascalCaseDash(); properties.Add(normalizedName, property.Value); } // Extract all other attributes from the tag helper, which are passed as IHtmlContent foreach (var pair in output.Attributes) { // Check it's not a reserved property name if (!InternalProperties.Contains(pair.Name)) { var normalizedName = pair.Name.ToPascalCaseDash(); if (!properties.ContainsKey(normalizedName)) { properties.Add(normalizedName, pair.Value.ToString()); } } } if (string.IsNullOrWhiteSpace(Type)) { Type = output.TagName; } if (string.IsNullOrWhiteSpace(Cache) && output.Attributes.ContainsName("cache-id")) { Cache = Convert.ToString(output.Attributes["cache-id"].Value); } if (string.IsNullOrWhiteSpace(Context) && output.Attributes.ContainsName("cache-context")) { Context = Convert.ToString(output.Attributes["cache-context"].Value); } if (string.IsNullOrWhiteSpace(Tag) && output.Attributes.ContainsName("cache-tag")) { Tag = Convert.ToString(output.Attributes["cache-tag"].Value); } if (!FixedDuration.HasValue && output.Attributes.ContainsName("cache-fixed-duration")) { TimeSpan timespan; if (TimeSpan.TryParse(Convert.ToString(output.Attributes["cache-fixed-duration"].Value), out timespan)) { FixedDuration = timespan; } } if (!SlidingDuration.HasValue && output.Attributes.ContainsName("cache-sliding-duration")) { TimeSpan timespan; if (TimeSpan.TryParse(Convert.ToString(output.Attributes["cache-sliding-duration"].Value), out timespan)) { SlidingDuration = timespan; } } var shape = await _shapeFactory.CreateAsync(Type, Arguments.From(properties)); if (output.Attributes.ContainsName("id")) { shape.Id = Convert.ToString(output.Attributes["id"].Value); } if (output.Attributes.ContainsName("alternate")) { shape.Metadata.Alternates.Add(Convert.ToString(output.Attributes["alternate"].Value)); } if (output.Attributes.ContainsName("wrapper")) { shape.Metadata.Wrappers.Add(Convert.ToString(output.Attributes["wrapper"].Value)); } tagHelperContext.Items.Add(typeof(IShape), shape); if (!string.IsNullOrWhiteSpace(Cache)) { var metadata = shape.Metadata; metadata.Cache(Cache); if (FixedDuration.HasValue) { metadata.Cache().WithExpiryAfter(FixedDuration.Value); } if (SlidingDuration.HasValue) { metadata.Cache().WithExpirySliding(SlidingDuration.Value); } if (!string.IsNullOrWhiteSpace(Context)) { var contexts = Context.Split(Separators, StringSplitOptions.RemoveEmptyEntries); metadata.Cache().AddContext(contexts); } if (!string.IsNullOrWhiteSpace(Tag)) { var tags = Tag.Split(Separators, StringSplitOptions.RemoveEmptyEntries); metadata.Cache().AddTag(tags); } } await output.GetChildContentAsync(); output.Content.SetHtmlContent(await _displayHelper.ShapeExecuteAsync(shape)); // We don't want any encapsulating tag around the shape output.TagName = null; }