/// <summary> /// Returns a valid HTML 4.01 "id" attribute value for an element with the given <paramref name="fullName"/>. /// </summary> /// <param name="viewContext">A <see cref="ViewContext"/> instance for the current scope.</param> /// <param name="fullName"> /// The fully-qualified expression name, ignoring the current model. Also the original HTML element name. /// </param> /// <param name="invalidCharReplacement"> /// The <see cref="string"/> (normally a single <see cref="char"/>) to substitute for invalid characters in /// <paramref name="fullName"/>. /// </param> /// <returns> /// Valid HTML 4.01 "id" attribute value for an element with the given <paramref name="fullName"/>. /// </returns> /// <remarks> /// Similar to <see cref="TagBuilder.CreateSanitizedId"/> but caches value for repeated invocations. /// </remarks> public static string CreateSanitizedId(ViewContext viewContext, string fullName, string invalidCharReplacement) { if (viewContext == null) { throw new ArgumentNullException(nameof(viewContext)); } if (invalidCharReplacement == null) { throw new ArgumentNullException(nameof(invalidCharReplacement)); } if (string.IsNullOrEmpty(fullName)) { return(string.Empty); } // Check cache to avoid whatever TagBuilder.CreateSanitizedId() may do. var items = viewContext.HttpContext.Items; object previousNameAndIdObject; PreviousNameAndId previousNameAndId = null; if (items.TryGetValue(PreviousNameAndIdKey, out previousNameAndIdObject) && (previousNameAndId = (PreviousNameAndId)previousNameAndIdObject) != null && string.Equals(previousNameAndId.FullName, fullName, StringComparison.Ordinal)) { return(previousNameAndId.SanitizedId); } var sanitizedId = TagBuilder.CreateSanitizedId(fullName, invalidCharReplacement); if (previousNameAndId == null) { // Do not create a PreviousNameAndId when TagBuilder.CreateSanitizedId() only examined fullName. if (string.Equals(fullName, sanitizedId, StringComparison.Ordinal)) { return(sanitizedId); } previousNameAndId = new PreviousNameAndId(); items[PreviousNameAndIdKey] = previousNameAndId; } previousNameAndId.FullName = fullName; previousNameAndId.SanitizedId = sanitizedId; return(previousNameAndId.SanitizedId); }
/// <summary> /// Returns the full HTML element name for the specified <paramref name="expression"/>. /// </summary> /// <param name="viewContext">A <see cref="ViewContext"/> instance for the current scope.</param> /// <param name="expression">Expression name, relative to the current model.</param> /// <returns>Fully-qualified expression name for <paramref name="expression"/>.</returns> /// <remarks> /// Similar to <see cref="TemplateInfo.GetFullHtmlFieldName"/> but caches value for repeated invocations. /// </remarks> public static string GetFullHtmlFieldName(ViewContext viewContext, string expression) { var htmlFieldPrefix = viewContext.ViewData.TemplateInfo.HtmlFieldPrefix; if (string.IsNullOrEmpty(expression)) { return(htmlFieldPrefix); } if (string.IsNullOrEmpty(htmlFieldPrefix)) { return(expression); } // Need to concatenate. See if we've already done that. IDictionary <object, object?> items = viewContext.HttpContext.Items; PreviousNameAndId? previousNameAndId = null; if (items.TryGetValue(previousNameAndIdKey, out var previousNameAndIdObject) && (previousNameAndId = (PreviousNameAndId?)previousNameAndIdObject) != null && string.Equals(previousNameAndId.HtmlFieldPrefix, htmlFieldPrefix, StringComparison.Ordinal) && string.Equals(previousNameAndId.Expression, expression, StringComparison.Ordinal)) { return(previousNameAndId.OutputFullName); } if (previousNameAndId is null) { previousNameAndId = new PreviousNameAndId(); items[previousNameAndIdKey] = previousNameAndId; } previousNameAndId.HtmlFieldPrefix = htmlFieldPrefix; previousNameAndId.Expression = expression; if (expression.StartsWith("[", StringComparison.Ordinal)) { // The expression might represent an indexer access, in which case with a 'dot' would be invalid. previousNameAndId.OutputFullName = htmlFieldPrefix + expression; } else { previousNameAndId.OutputFullName = htmlFieldPrefix + "." + expression; } return(previousNameAndId.OutputFullName); }