/// <summary> /// Creates a new <see cref="ModelExplorer"/>. /// </summary> /// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param> /// <param name="container">The container <see cref="ModelExplorer"/>.</param> /// <param name="metadata">The <see cref="ModelMetadata"/>.</param> /// <param name="modelAccessor">A model accessor function..</param> public ModelExplorer( IModelMetadataProvider metadataProvider, ModelExplorer container, ModelMetadata metadata, Func<object, object> modelAccessor) { if (metadataProvider == null) { throw new ArgumentNullException(nameof(metadataProvider)); } if (container == null) { throw new ArgumentNullException(nameof(container)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } _metadataProvider = metadataProvider; Container = container; Metadata = metadata; _modelAccessor = modelAccessor; }
/// <summary> /// Invokes the view component. /// </summary> /// <param name="tableElementId">The ID of the table DOM element.</param> /// <param name="modelExplorer">The model explorer for the collection containing the table contents.</param> /// <param name="properties">The name of the properties of the model object to show in the table.</param> /// <param name="hiddenValues">Hidden values that should be included with the properties.</param> /// <param name="orderByProp">The property to order the rows by.</param> /// <param name="textAreas">Whether to render the properties in multi-line text areas.</param> /// <param name="startMinRows">The minimum number of rows in the table to start with.</param> /// <param name="defaultValues">The default values for each column, if any.</param> /// <param name="dropDownLists">The drop down lists to use, if any.</param> /// <param name="subPanelConfig">The configuration object for the subpanel (if any).</param> public IViewComponentResult Invoke( string tableElementId, ModelExplorer modelExplorer, string[] properties, IDictionary<string, string> hiddenValues, string orderByProp, int startMinRows, bool textAreas, IDictionary<string, object> defaultValues, IList<DropDownList> dropDownLists, SubPanelConfig subPanelConfig) { var props = properties.Where(prop => prop != null).ToArray(); var collection = GetOrderedCollection(modelExplorer, orderByProp); var elementMetadata = modelExplorer.Metadata.ElementMetadata; string collectionName = modelExplorer.Metadata.PropertyName; JArray columns = GetColumnInfo ( props, hiddenValues, textAreas, defaultValues, dropDownLists, elementMetadata ); var initDataProperties = subPanelConfig == null ? props : props.Union(new[] { subPanelConfig.ContentsPropertyName }); JArray initData = GetInitialData ( hiddenValues, collection, dropDownLists, elementMetadata, initDataProperties ); return View ( new DynamicTableConfig ( tableElementId, collectionName, columns, initData, startMinRows, textAreas, dropDownLists, subPanelConfig ) ); }
/// <summary> /// Initializes a new instance of the <see cref="ModelExpression"/> class. /// </summary> /// <param name="name"> /// String representation of the <see cref="System.Linq.Expressions.Expression"/> of interest. /// </param> /// <param name="modelExplorer"> /// Includes the model and metadata about the <see cref="System.Linq.Expressions.Expression"/> of interest. /// </param> public ModelExpression(string name, ModelExplorer modelExplorer) { if (name == null) { throw new ArgumentNullException(nameof(name)); } if (modelExplorer == null) { throw new ArgumentNullException(nameof(modelExplorer)); } Name = name; ModelExplorer = modelExplorer; }
public JsTreeTagHelperTests() { JsTree tree = new JsTree(); tree.SelectedIds.Add(4567); tree.SelectedIds.Add(12345); tree.Nodes.Add(new JsTreeNode("Test")); tree.Nodes[0].Nodes.Add(new JsTreeNode(12345, "Test1")); tree.Nodes[0].Nodes.Add(new JsTreeNode(23456, "Test2")); EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider(); ModelExplorer explorer = new ModelExplorer(provider, provider.GetMetadataForProperty(typeof(JsTreeView), "JsTree"), tree); helper = new JsTreeTagHelper(); helper.For = new ModelExpression("JsTree", explorer); output = new TagHelperOutput("div", new TagHelperAttributeList(), (useCachedResult, encoder) => null); }
/// <summary> /// Returns a collection, ordered by the property with the given name. /// </summary> private IEnumerable<object> GetOrderedCollection(ModelExplorer modelExplorer, string orderByProp) { var orderProp = modelExplorer.Metadata.ElementMetadata.Properties[orderByProp]; var collection = (modelExplorer.Model as IEnumerable)?.Cast<object>(); if (collection == null) return null; if (orderProp.ModelType == typeof(string)) return collection.OrderBy(obj => (string) orderProp.PropertyGetter(obj)); else if (orderProp.ModelType == typeof(int)) return collection.OrderBy(obj => (int) orderProp.PropertyGetter(obj)); else throw new InvalidOperationException("Unsupported order property type."); }
private string GetInputType(ModelExplorer modelExplorer, out string inputTypeHint) { foreach (var hint in GetInputTypeHints(modelExplorer)) { string inputType; if (_defaultInputTypes.TryGetValue(hint, out inputType)) { inputTypeHint = hint; return inputType; } } inputTypeHint = InputType.Text.ToString().ToLowerInvariant(); return inputTypeHint; }
// Get a fall-back format based on the metadata. private string GetFormat(ModelExplorer modelExplorer, string inputTypeHint, string inputType) { string format; string rfc3339Format; if (string.Equals("decimal", inputTypeHint, StringComparison.OrdinalIgnoreCase) && string.Equals("text", inputType, StringComparison.Ordinal) && string.IsNullOrEmpty(modelExplorer.Metadata.EditFormatString)) { // Decimal data is edited using an <input type="text"/> element, with a reasonable format. // EditFormatString has precedence over this fall-back format. format = "{0:0.00}"; } else if (_rfc3339Formats.TryGetValue(inputType, out rfc3339Format) && ViewContext.Html5DateRenderingMode == Html5DateRenderingMode.Rfc3339 && !modelExplorer.Metadata.HasNonDefaultEditFormat && (typeof(DateTime) == modelExplorer.Metadata.UnderlyingOrModelType || typeof(DateTimeOffset) == modelExplorer.Metadata.UnderlyingOrModelType)) { // Rfc3339 mode _may_ override EditFormatString in a limited number of cases e.g. EditFormatString // must be a default format (i.e. came from a built-in [DataType] attribute). format = rfc3339Format; } else { // Otherwise use EditFormatString, if any. format = modelExplorer.Metadata.EditFormatString; } return format; }
private TagBuilder GenerateTextBox(ModelExplorer modelExplorer, string inputTypeHint, string inputType) { var format = Format; if (string.IsNullOrEmpty(format)) { format = GetFormat(modelExplorer, inputTypeHint, inputType); } var htmlAttributes = new Dictionary<string, object> { { "type", inputType } }; if (string.Equals(inputType, "file") && string.Equals(inputTypeHint, TemplateRenderer.IEnumerableOfIFormFileName)) { htmlAttributes["multiple"] = "multiple"; } return Generator.GenerateTextBox( ViewContext, modelExplorer, For.Name, value: modelExplorer.Model, format: format, htmlAttributes: htmlAttributes); }
private TagBuilder GenerateRadio(ModelExplorer modelExplorer) { // Note empty string is allowed. if (Value == null) { throw new InvalidOperationException(Resources.FormatInputTagHelper_ValueRequired( "<input>", nameof(Value).ToLowerInvariant(), "type", "radio")); } return Generator.GenerateRadioButton( ViewContext, modelExplorer, For.Name, Value, isChecked: null, htmlAttributes: null); }
private void GenerateCheckBox(ModelExplorer modelExplorer, TagHelperOutput output) { if (typeof(bool) != modelExplorer.ModelType) { throw new InvalidOperationException(Resources.FormatInputTagHelper_InvalidExpressionResult( "<input>", ForAttributeName, modelExplorer.ModelType.FullName, typeof(bool).FullName, "type", "checkbox")); } // Prepare to move attributes from current element to <input type="checkbox"/> generated just below. var htmlAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); // Perf: Avoid allocating enumerator // Construct attributes correctly (first attribute wins). for (var i = 0; i < output.Attributes.Count; i++) { var attribute = output.Attributes[i]; if (!htmlAttributes.ContainsKey(attribute.Name)) { htmlAttributes.Add(attribute.Name, attribute.Value); } } var checkBoxTag = Generator.GenerateCheckBox( ViewContext, modelExplorer, For.Name, isChecked: null, htmlAttributes: htmlAttributes); if (checkBoxTag != null) { // Do not generate current element's attributes or tags. Instead put both <input type="checkbox"/> and // <input type="hidden"/> into the output's Content. output.Attributes.Clear(); output.TagName = null; var renderingMode = output.TagMode == TagMode.SelfClosing ? TagRenderMode.SelfClosing : TagRenderMode.StartTag; checkBoxTag.TagRenderMode = renderingMode; output.Content.AppendHtml(checkBoxTag); var hiddenForCheckboxTag = Generator.GenerateHiddenForCheckbox(ViewContext, modelExplorer, For.Name); if (hiddenForCheckboxTag != null) { hiddenForCheckboxTag.TagRenderMode = renderingMode; if (ViewContext.FormContext.CanRenderAtEndOfForm) { ViewContext.FormContext.EndOfFormContent.Add(hiddenForCheckboxTag); } else { output.Content.AppendHtml(hiddenForCheckboxTag); } } } }
// A variant of TemplateRenderer.GetViewNames(). Main change relates to bool? handling. private static IEnumerable<string> GetInputTypeHints(ModelExplorer modelExplorer) { if (!string.IsNullOrEmpty(modelExplorer.Metadata.TemplateHint)) { yield return modelExplorer.Metadata.TemplateHint; } if (!string.IsNullOrEmpty(modelExplorer.Metadata.DataTypeName)) { yield return modelExplorer.Metadata.DataTypeName; } // In most cases, we don't want to search for Nullable<T>. We want to search for T, which should handle // both T and Nullable<T>. However we special-case bool? to avoid turning an <input/> into a <select/>. var fieldType = modelExplorer.ModelType; if (typeof(bool?) != fieldType) { fieldType = modelExplorer.Metadata.UnderlyingOrModelType; } foreach (string typeName in TemplateRenderer.GetTypeNames(modelExplorer.Metadata, fieldType)) { yield return typeName; } }
public bool Visited(ModelExplorer modelExplorer) { return _visitedObjects.Contains(modelExplorer.Model ?? modelExplorer.Metadata.ModelType); }
/// <summary> /// Creates a new <see cref="ModelExplorer"/>. /// </summary> /// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param> /// <param name="container">The container <see cref="ModelExplorer"/>.</param> /// <param name="metadata">The <see cref="ModelMetadata"/>.</param> /// <param name="model">The model object. May be <c>null</c>.</param> public ModelExplorer( IModelMetadataProvider metadataProvider, ModelExplorer container, ModelMetadata metadata, object model) { if (metadataProvider == null) { throw new ArgumentNullException(nameof(metadataProvider)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } _metadataProvider = metadataProvider; Container = container; Metadata = metadata; _model = model; }