/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="RelationshipViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, RelationshipAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); Contract.Requires(attribute.Key, nameof(attribute.Key)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ currentTopic.Attributes.TryGetValue(attribute.Key, out var value); var model = new AttributeViewModel<RelationshipAttributeDescriptorViewModel>(currentTopic, attribute) { Value = CleanArray(value) }; /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(model); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="TextAreaViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, TextAreaAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var viewModel = new AttributeViewModel<TextAreaAttributeDescriptorViewModel>(currentTopic, attribute); /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(viewModel); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="TokenizedTopicListViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, TokenizedTopicListAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var model = new TokenizedTopicListAttributeViewModel(currentTopic, attribute); /*------------------------------------------------------------------------------------------------------------------------ | Set model values \-----------------------------------------------------------------------------------------------------------------------*/ model.SelectedTopics = GetSelectedTopics(model.Value); /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(model); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="FilePathViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, FilePathAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var model = new FilePathAttributeViewModel(currentTopic, attribute) { InheritedValue = GetInheritedValue(attribute.Key!, attribute) }; /*------------------------------------------------------------------------------------------------------------------------ | Set model values \-----------------------------------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(model); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="LastModifiedByViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, LastModifiedByAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); Contract.Requires(attribute.Key, nameof(attribute.Key)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ currentTopic.Attributes.TryGetValue(attribute.Key, out var value); var model = new LastModifiedByAttributeViewModel(currentTopic, attribute) { CurrentValue = value, Value = HttpContext.User.Identity.Name }; /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(model); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="InstructionViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, InstructionAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; return View(new AttributeViewModel<InstructionAttributeDescriptorViewModel>(currentTopic, attribute)); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="NestedTopicListViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, NestedTopicListAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); Contract.Requires(attribute.Key, nameof(attribute.Key)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var viewModel = new NestedTopicListAttributeViewModel(currentTopic, attribute); /*------------------------------------------------------------------------------------------------------------------------ | Set model values \-----------------------------------------------------------------------------------------------------------------------*/ if (HttpContext.Request.Query.TryGetValue("IsNew", out var action)) { viewModel.IsNew = action.FirstOrDefault().Equals("true", StringComparison.OrdinalIgnoreCase); } viewModel.UniqueKey = currentTopic.UniqueKey; viewModel.WebPath = currentTopic.WebPath; /*------------------------------------------------------------------------------------------------------------------------ | Establish nested topic container, if needed \-----------------------------------------------------------------------------------------------------------------------*/ if (!viewModel.IsNew) { var topic = _topicRepository.Load(viewModel.UniqueKey); Contract.Assume(topic, $"The topic with the unique key '{viewModel.UniqueKey}' could not be found."); if (!topic.Children.Contains(attribute.Key)) { var topicContainer = TopicFactory.Create(attribute.Key, "List", topic); _topicRepository.Save(topicContainer); } } /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(viewModel); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="TopicReferenceViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, TopicReferenceAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Set configuration values \-----------------------------------------------------------------------------------------------------------------------*/ //### TODO 6.0.0: Remove hard-coded reference to BaseTopic; this is only needed for backward compatibility with 5.0.0. var isBaseTopic = attribute.Key.Equals("BaseTopic", StringComparison.OrdinalIgnoreCase); if (attribute.UseCurrentContentType || isBaseTopic) { attribute = attribute with { AttributeKey = "ContentType", AttributeValue = currentTopic.ContentType, AutoPostBack = isBaseTopic? true : attribute.AutoPostBack }; } /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var viewModel = new AttributeViewModel<TopicReferenceAttributeDescriptorViewModel>(currentTopic, attribute); /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(viewModel); } } // Class
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="LastModifiedViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, LastModifiedAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); Contract.Requires(attribute.Key, nameof(attribute.Key)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Set model defaults \-----------------------------------------------------------------------------------------------------------------------*/ currentTopic.Attributes.TryGetValue(attribute.Key, out var currentValue); if (currentTopic.LastModified != DateTime.MinValue) { currentValue = currentTopic.LastModified.ToString(CultureInfo.InvariantCulture); } var value = DateTime.Now.ToString(CultureInfo.InvariantCulture); /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var model = new LastModifiedAttributeViewModel(currentTopic, attribute) { CurrentValue = currentValue, Value = value }; /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(model); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="HtmlViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, HtmlAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Set configuration values \-----------------------------------------------------------------------------------------------------------------------*/ if (attribute.Height is null || attribute.Height is 0 && attribute.Rows is not null) { attribute = attribute with { Height = attribute.Rows * 20 }; } /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var viewModel = new AttributeViewModel<HtmlAttributeDescriptorViewModel>(currentTopic, attribute); /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(viewModel); } } // Class
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="NumberViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, NumberAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var viewModel = new AttributeViewModel<NumberAttributeDescriptorViewModel>(currentTopic, attribute); /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(viewModel); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="FileListViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, FileListAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var model = new FileListAttributeViewModel(currentTopic, attribute) { AbsolutePath = _webHostEnvironment.ContentRootPath + attribute.Path }; /*------------------------------------------------------------------------------------------------------------------------ | Set model values \-----------------------------------------------------------------------------------------------------------------------*/ foreach (var file in GetFiles(model)) { model.Files.Add(file); }; /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(model); }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="ContentTypeListViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, ContentTypeListAttributeDescriptorViewModel? attributeDescriptor = null, IEnumerable<PermittedContentTypeViewModel>? values = null, string? onModalClose = null ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var viewModel = new ContentTypeListViewModel() { CurrentTopic = currentTopic, AttributeKey = attributeDescriptor?.Key, EnableModal = attributeDescriptor?.EnableModal?? false, OnModalClose = onModalClose }; /*------------------------------------------------------------------------------------------------------------------------ | Set label \-----------------------------------------------------------------------------------------------------------------------*/ viewModel.TopicList.Add( new() { Value = null, Text = "Add a child topic…" } ); /*------------------------------------------------------------------------------------------------------------------------ | Add values to view model \-----------------------------------------------------------------------------------------------------------------------*/ foreach (var contentType in values.OrderBy(c => c.Title)) { viewModel.TopicList.Add( new() { Value = getValue(contentType.Key!), Text = contentType.Title } ); } /*------------------------------------------------------------------------------------------------------------------------ | Get content type >------------------------------------------------------------------------------------------------------------------------- | If the database is uninitialized, the content type won't be found. In that case, return an empty view, which will | effectively hide the component. If the topic cannot be found, assume it is a new topic and attempt to load the parent | for context. \-----------------------------------------------------------------------------------------------------------------------*/ var contentTypes = _topicRepository.GetContentTypeDescriptors(); var actualTopic = _topicRepository.Load(currentTopic.Id)?? _topicRepository.Load(currentTopic.Parent?.Id?? Int32.MinValue); var actualContentType = contentTypes.GetValue(currentTopic.ContentType!); if (actualContentType is null || actualTopic is null) { return View(viewModel); } /*------------------------------------------------------------------------------------------------------------------------ | Get permitted content types for container >------------------------------------------------------------------------------------------------------------------------- | Containers provide special rules allowing the permitted content types to be defined—or even expanded—on the topic | instance itself, instead of exclusively on the content type descriptor. This is useful since often containers are meant | to organize a specific type of content. For example, a Container called "Forms" might be used exclusively to organized | Form topics. \-----------------------------------------------------------------------------------------------------------------------*/ if (actualContentType.Key.Equals("Container", StringComparison.OrdinalIgnoreCase)) { var permittedContentTypes = actualTopic .Relationships .GetValues("ContentTypes") .Select(c => new SelectListItem() { Value = getValue(c.Key), Text = c.Title } ); foreach (var contentType in permittedContentTypes) { viewModel.TopicList.Add(contentType); } } /*------------------------------------------------------------------------------------------------------------------------ | Get implicit values >------------------------------------------------------------------------------------------------------------------------- | If no permitted content types are explicitly defined on the content type—or the topic, in the case of a container—then | we instead load a generic list of content types. We don't want to display all content types, however, as many make | little sense outside of specific contexts. For instance, most content types that derive from Items only make sense as | nested topics. Similarly, specialized types like Home might only make sense in one location. To facilitate this, only | content types explicitly annotated as "implicitly permitted", and which are not marked as hidden are displayed. This | typically include the Page content type, and popular derivatives of it, such as Content List. \-----------------------------------------------------------------------------------------------------------------------*/ if (viewModel.TopicList.Count is 1 && !actualContentType.DisableChildTopics) { var implicitValues = contentTypes .Where(c => actualContentType.Equals("Container") || c.Attributes.GetBoolean("ImplicitlyPermitted", false)) .Where(c => !c.IsHidden) .OrderBy(c => c.Title) .Select(c => new SelectListItem { Value = getValue(c.Key), Text = c.Title } ); foreach (var contentType in implicitValues) { viewModel.TopicList.Add(contentType); } } /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(viewModel); /*------------------------------------------------------------------------------------------------------------------------ | Helper functions \-----------------------------------------------------------------------------------------------------------------------*/ string getValue(string contentType) => $"{Url.Action("Edit")}" + $"/{attributeDescriptor?.Key}" + $"?IsNew=true" + $"&IsModal={attributeDescriptor?.EnableModal?? false}" + $"&ContentType={contentType}"; }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="ReflexiveViewComponent"/>. /// </summary> public async Task<IViewComponentResult> InvokeAsync( EditingTopicViewModel currentTopic, ReflexiveAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish snapshot of previously saved attribute descriptor \-----------------------------------------------------------------------------------------------------------------------*/ var topic = _topicRepository.Load(currentTopic.UniqueKey); var reflexiveViewModel = (AttributeDescriptorViewModel?)null; if (topic?.ContentType.EndsWith("AttributeDescriptor", StringComparison.OrdinalIgnoreCase)?? false) { reflexiveViewModel = (AttributeDescriptorViewModel?)await _topicMappingService.MapAsync(topic).ConfigureAwait(false); } if (reflexiveViewModel is null) { reflexiveViewModel = new(); } /*------------------------------------------------------------------------------------------------------------------------ | Establish hybrid view model >------------------------------------------------------------------------------------------------------------------------- | The ParentAttributeDescriptor will be of the target type expected for the view component that will be executed. But it | should use the core AttributeDescriptor attributes of the current attribute, so it shows up in the same location with | the same title and description as defined for the ReflexiveAttributeDescriptorViewModel. \-----------------------------------------------------------------------------------------------------------------------*/ reflexiveViewModel = reflexiveViewModel with { Key = attribute.Key, Description = attribute.Description, DisplayGroup = attribute.DisplayGroup, DefaultValue = attribute.DefaultValue, IsRequired = attribute.IsRequired, SortOrder = attribute.SortOrder, Title = attribute.Title }; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var viewModel = new AttributeViewModel<AttributeDescriptorViewModel>(currentTopic, reflexiveViewModel); /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(viewModel); } } // Class
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="TopicListViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, TopicListAttributeDescriptorViewModel attribute, string? htmlFieldPrefix = null ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); Contract.Requires(currentTopic.ContentType, nameof(currentTopic.ContentType)); Contract.Requires(attribute.Key, nameof(attribute.Key)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var viewModel = new TopicListAttributeViewModel(currentTopic, attribute); /*------------------------------------------------------------------------------------------------------------------------ | Set default value \-----------------------------------------------------------------------------------------------------------------------*/ var defaultValue = currentTopic.Attributes.ContainsKey(attribute.Key)? currentTopic.Attributes[attribute.Key] : null; /*------------------------------------------------------------------------------------------------------------------------ | Get root topic \-----------------------------------------------------------------------------------------------------------------------*/ var rootTopic = (Topic?)null; if (attribute.RelativeTopicBase is not null) { var baseTopic = _topicRepository.Load(currentTopic.UniqueKey); Contract.Assume(baseTopic, $"The topic with the key '{currentTopic.UniqueKey}' could not be located."); if (String.IsNullOrEmpty(currentTopic.Key)) { baseTopic = TopicFactory.Create("NewTopic", currentTopic.ContentType, baseTopic); baseTopic.Parent?.Children.Remove(baseTopic); } rootTopic = attribute.RelativeTopicBase switch { "CurrentTopic" => baseTopic, "ParentTopic" => baseTopic.Parent, "GrandparentTopic" => (Topic?)baseTopic.Parent?.Parent, "ContentTypeDescriptor" => (Topic?)_topicRepository.GetContentTypeDescriptors().FirstOrDefault(t => t.Key.Equals(baseTopic.ContentType, StringComparison.Ordinal)), _ => baseTopic }; } else if (attribute.RootTopic is not null) { rootTopic = _topicRepository.Load(attribute.RootTopic.UniqueKey); } if (rootTopic is not null && !String.IsNullOrEmpty(attribute.RelativeTopicPath)) { rootTopic = rootTopic.GetByUniqueKey(rootTopic.GetUniqueKey() + ":" + attribute.RelativeTopicPath); } /*------------------------------------------------------------------------------------------------------------------------ | Get values \-----------------------------------------------------------------------------------------------------------------------*/ var topics = GetTopics( rootTopic, attribute.AttributeKey, attribute.AttributeValue ); /*------------------------------------------------------------------------------------------------------------------------ | Set label \-----------------------------------------------------------------------------------------------------------------------*/ if (!String.IsNullOrEmpty(viewModel.InheritedValue)) { setLabel(viewModel.InheritedValue, "inherited value"); } else if (!String.IsNullOrEmpty(viewModel.AttributeDescriptor.DefaultValue)) { setLabel(viewModel.AttributeDescriptor.DefaultValue, "default value"); } else if (!String.IsNullOrEmpty(viewModel.AttributeDescriptor.ImplicitValue)) { setLabel(viewModel.AttributeDescriptor.ImplicitValue, "implicit default"); } else { setLabel(attribute.DefaultLabel?? "Select an option…"); } /*------------------------------------------------------------------------------------------------------------------------ | Get values from repository \-----------------------------------------------------------------------------------------------------------------------*/ foreach (var topic in topics) { var title = viewModel.TopicList.Any(t => t.Text == topic.Title)? $"{topic.Title} ({topic.Key})" : topic.Title; var value = getValue(topic); viewModel.TopicList.Add( new() { Value = value, Text = title, Selected = value == defaultValue } ); } /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(viewModel); /*------------------------------------------------------------------------------------------------------------------------ | Function: Get Value \-----------------------------------------------------------------------------------------------------------------------*/ string getValue(QueryResultTopicViewModel topic) => ReplaceTokens(topic, "{" + attribute.ValueProperty + "}"); /*------------------------------------------------------------------------------------------------------------------------ | Function: Set Label \-----------------------------------------------------------------------------------------------------------------------*/ void setLabel(string value, string? contextualLabel = null) { var inheritedTopic = topics.Where(t => t.Key == value).FirstOrDefault(); var label = inheritedTopic?.Title ?? value; if (contextualLabel is not null) { label += " (" + contextualLabel + ")"; } viewModel?.TopicList.Add( new() { Value = "", Text = label } ); } }
/*========================================================================================================================== | METHOD: INVOKE \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Assembles the view model for the <see cref="IncomingRelationshipViewComponent"/>. /// </summary> public IViewComponentResult Invoke( EditingTopicViewModel currentTopic, IncomingRelationshipAttributeDescriptorViewModel attribute, string htmlFieldPrefix ) { /*------------------------------------------------------------------------------------------------------------------------ | Validate parameters \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(currentTopic, nameof(currentTopic)); Contract.Requires(attribute, nameof(attribute)); Contract.Requires(attribute.Key, nameof(attribute.Key)); /*------------------------------------------------------------------------------------------------------------------------ | Set HTML prefix \-----------------------------------------------------------------------------------------------------------------------*/ ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix; /*------------------------------------------------------------------------------------------------------------------------ | Establish view model \-----------------------------------------------------------------------------------------------------------------------*/ var model = new IncomingRelationshipAttributeViewModel(currentTopic, attribute); /*------------------------------------------------------------------------------------------------------------------------ | Set incoming relationships >------------------------------------------------------------------------------------------------------------------------- | ### NOTE JJC20200929: This would be a lot cleaner using the ITopicMappingService. But that would introduce an additional | dependency on the StandardEditorComposer, which would be a breaking change. We can reevaluate this in the future if | other view components would benefit from this. \-----------------------------------------------------------------------------------------------------------------------*/ var topic = _topicRepository.Load(currentTopic.UniqueKey); Contract.Assume(topic, $"The target topic with the unique key '{currentTopic.UniqueKey}' could not be found."); foreach(var relatedTopic in topic.IncomingRelationships.GetValues(attribute.RelationshipKey?? attribute.Key)) { if (!String.IsNullOrWhiteSpace(attribute.AttributeKey)) { var attributeValue = relatedTopic.Attributes.GetValue(attribute.AttributeKey, ""); if (attribute.AttributeKey.Equals("ContentType", StringComparison.OrdinalIgnoreCase)) { attributeValue = relatedTopic.ContentType; } if (!attributeValue.Equals(attribute.AttributeValue, StringComparison.OrdinalIgnoreCase)) { continue; } } var relatedViewModel = new CoreTopicViewModel { Key = relatedTopic.Key, ContentType = relatedTopic.ContentType, UniqueKey = relatedTopic.GetUniqueKey(), WebPath = relatedTopic.GetWebPath(), Title = relatedTopic.Title }; model.RelatedTopics.Add(relatedViewModel); } /*------------------------------------------------------------------------------------------------------------------------ | Return view with view model \-----------------------------------------------------------------------------------------------------------------------*/ return View(model); }