public void CopyHtmlAttribute_DoesNotOverrideAttributes()
        {
            // Arrange
            var attributeName = "hello";
            var tagHelperOutput = new TagHelperOutput(
                "p",
                attributes: new Dictionary<string, object>()
                {
                    { attributeName, "world2" }
                });
            var expectedAttribute = new KeyValuePair<string, object>(attributeName, "world2");
            var tagHelperContext = new TagHelperContext(
                allAttributes: new Dictionary<string, object>(StringComparer.Ordinal)
                {
                    { attributeName, "world" }
                },
                items: new Dictionary<object, object>(),
                uniqueId: "test",
                getChildContentAsync: () =>
                {
                    var tagHelperContent = new DefaultTagHelperContent();
                    tagHelperContent.Append("Something Else");
                    return Task.FromResult<TagHelperContent>(tagHelperContent);
                });

            // Act
            tagHelperOutput.CopyHtmlAttribute(attributeName, tagHelperContext);

            // Assert
            var attribute = Assert.Single(tagHelperOutput.Attributes);
            Assert.Equal(expectedAttribute, attribute);
        }
Exemplo n.º 2
0
        /// <inheritdoc />
        /// <remarks>
        /// Does nothing unless <see cref="FormContext.FormData"/> contains a
        /// <see cref="SelectTagHelper.SelectedValuesFormDataKey"/> entry and that entry is a non-empty
        /// <see cref="ICollection{string}"/> instance. Also does nothing if the associated &lt;option&gt; is already
        /// selected.
        /// </remarks>
        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            // Pass through attributes that are also well-known HTML attributes.
            if (Value != null)
            {
                output.CopyHtmlAttribute(nameof(Value), context);
            }

            // Nothing to do if this <option/> is already selected.
            if (!output.Attributes.ContainsName("selected"))
            {
                // Is this <option/> element a child of a <select/> element the SelectTagHelper targeted?
                object formDataEntry;
                ViewContext.FormContext.FormData.TryGetValue(
                    SelectTagHelper.SelectedValuesFormDataKey,
                    out formDataEntry);

                // ... And did the SelectTagHelper determine any selected values?
                var selectedValues = formDataEntry as ICollection<string>;
                if (selectedValues != null && selectedValues.Count != 0)
                {
                    // Encode all selected values for comparison with element content.
                    var encodedValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
                    foreach (var selectedValue in selectedValues)
                    {
                        encodedValues.Add(Generator.Encode(selectedValue));
                    }

                    // Select this <option/> element if value attribute or content matches a selected value. Callers
                    // encode values as-needed while executing child content. But TagHelperOutput itself
                    // encodes attribute values later, when start tag is generated.
                    bool selected;
                    if (Value != null)
                    {
                        selected = selectedValues.Contains(Value);
                    }
                    else if (output.IsContentModified)
                    {
                        selected = encodedValues.Contains(output.Content.GetContent());
                    }
                    else
                    {
                        var childContent = await context.GetChildContentAsync();
                        selected = encodedValues.Contains(childContent.GetContent());
                    }

                    if (selected)
                    {
                        output.Attributes.Add("selected", "selected");
                    }
                }
            }
        }
Exemplo n.º 3
0
 /// <inheritdoc />
 public override void Process(TagHelperContext context, TagHelperOutput output)
 {
     if (FileVersion)
     {
         EnsureFileVersionProvider();
         output.Attributes[SrcAttributeName] = _fileVersionProvider.AddFileVersionToPath(Src);
     }
     else
     {
         // Pass through attribute that is also a well-known HTML attribute.
         output.CopyHtmlAttribute(SrcAttributeName, context);
     }
 }
Exemplo n.º 4
0
        /// <inheritdoc />
        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            // Pass through attribute that is also a well-known HTML attribute.
            if (Src != null)
            {
                output.CopyHtmlAttribute(SrcAttributeName, context);
            }

            var modeResult = AttributeMatcher.DetermineMode(context, ModeDetails);

            modeResult.LogDetails(Logger, this, context.UniqueId, ViewContext.View.Path);

            if (!modeResult.FullMatches.Any())
            {
                // No attributes matched so we have nothing to do
                return;
            }

            // Get the highest matched mode
            var mode = modeResult.FullMatches.Select(match => match.Mode).Max();

            // NOTE: Values in TagHelperOutput.Attributes may already be HTML-encoded.
            var attributes = new TagHelperAttributeList(output.Attributes);

            var builder = new DefaultTagHelperContent();
            var originalContent = await context.GetChildContentAsync();

            if (mode == Mode.Fallback && string.IsNullOrEmpty(SrcInclude) || mode == Mode.FileVersion)
            {
                // No globbing to do, just build a <script /> tag to match the original one in the source file
                // Or just add file version to the script tag.
                BuildScriptTag(originalContent, attributes, builder);
            }
            else
            {
                BuildGlobbedScriptTags(originalContent, attributes, builder);
            }

            if (mode == Mode.Fallback)
            {
                BuildFallbackBlock(attributes, builder);
            }

            // We've taken over tag rendering, so prevent rendering the outer tag
            output.TagName = null;
            output.Content.SetContent(builder);
        }
Exemplo n.º 5
0
        /// <inheritdoc />
        /// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks>
        /// <exception cref="InvalidOperationException">
        /// Thrown if <see cref="Format"/> is non-<c>null</c> but <see cref="For"/> is <c>null</c>.
        /// </exception>
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            // Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying
            // from a TagBuilder.
            if (InputTypeName != null)
            {
                output.CopyHtmlAttribute("type", context);
            }

            if (Value != null)
            {
                output.CopyHtmlAttribute(nameof(Value), context);
            }

            // Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient.
            // IHtmlGenerator will enforce name requirements.
            var metadata = For.Metadata;
            var modelExplorer = For.ModelExplorer;
            if (metadata == null)
            {
                throw new InvalidOperationException(Resources.FormatTagHelpers_NoProvidedMetadata(
                    "<input>",
                    ForAttributeName,
                    nameof(IModelMetadataProvider),
                    For.Name));
            }

            string inputType;
            string inputTypeHint;
            if (string.IsNullOrEmpty(InputTypeName))
            {
                // Note GetInputType never returns null.
                inputType = GetInputType(modelExplorer, out inputTypeHint);
            }
            else
            {
                inputType = InputTypeName.ToLowerInvariant();
                inputTypeHint = null;
            }

            // inputType may be more specific than default the generator chooses below.
            if (!output.Attributes.ContainsName("type"))
            {
                output.Attributes["type"] = inputType;
            }

            TagBuilder tagBuilder;
            switch (inputType)
            {
                case "checkbox":
                    GenerateCheckBox(modelExplorer, output);
                    return;

                case "hidden":
                    tagBuilder = Generator.GenerateHidden(
                        ViewContext,
                        modelExplorer,
                        For.Name,
                        value: For.Model,
                        useViewData: false,
                        htmlAttributes: null);
                    break;

                case "password":
                    tagBuilder = Generator.GeneratePassword(
                        ViewContext,
                        modelExplorer,
                        For.Name,
                        value: null,
                        htmlAttributes: null);
                    break;

                case "radio":
                    tagBuilder = GenerateRadio(modelExplorer);
                    break;

                default:
                    tagBuilder = GenerateTextBox(modelExplorer, inputTypeHint, inputType);
                    break;
            }

            if (tagBuilder != null)
            {
                // This TagBuilder contains the one <input/> element of interest. Since this is not the "checkbox"
                // special-case, output is a self-closing element no longer guaranteed.
                output.MergeAttributes(tagBuilder);
                output.Content.Append(tagBuilder.InnerHtml);
            }
        }
Exemplo n.º 6
0
        /// <inheritdoc />
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            string resolvedUrl;

            // Pass through attribute that is also a well-known HTML attribute.
            if (Href != null)
            {
                output.CopyHtmlAttribute(HrefAttributeName, context);

                // Resolve any application relative URLs (~/) now so they can be used in comparisons later.
                if (TryResolveUrl(Href, encodeWebRoot: false, resolvedUrl: out resolvedUrl))
                {
                    Href = resolvedUrl;
                }

                ProcessUrlAttribute(HrefAttributeName, output);
            }

            var modeResult = AttributeMatcher.DetermineMode(context, ModeDetails);

            modeResult.LogDetails(Logger, this, context.UniqueId, ViewContext.View.Path);

            if (!modeResult.FullMatches.Any())
            {
                // No attributes matched so we have nothing to do
                return;
            }

            // NOTE: Values in TagHelperOutput.Attributes may already be HTML-encoded.
            var attributes = new TagHelperAttributeList(output.Attributes);

            if (AppendVersion == true)
            {
                EnsureFileVersionProvider();

                var attributeStringValue = output.Attributes[HrefAttributeName]?.Value as string;
                if (attributeStringValue != null)
                {
                    output.Attributes[HrefAttributeName].Value =
                        _fileVersionProvider.AddFileVersionToPath(attributeStringValue);
                }
            }

            var builder = new DefaultTagHelperContent();

            // Get the highest matched mode
            var mode = modeResult.FullMatches.Select(match => match.Mode).Max();

            if (mode == Mode.GlobbedHref || mode == Mode.Fallback && !string.IsNullOrEmpty(HrefInclude))
            {
                BuildGlobbedLinkTags(attributes, builder);
                if (string.IsNullOrEmpty(Href))
                {
                    // Only HrefInclude is specified. Don't render the original tag.
                    output.TagName = null;
                    output.Content.SetContent(string.Empty);
                }
            }

            if (mode == Mode.Fallback)
            {
                if (TryResolveUrl(FallbackHref, encodeWebRoot: false, resolvedUrl: out resolvedUrl))
                {
                    FallbackHref = resolvedUrl;
                }

                BuildFallbackBlock(builder);
            }

            output.PostElement.SetContent(builder);
        }
Exemplo n.º 7
0
        /// <inheritdoc />
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.CopyHtmlAttribute(SrcAttributeName, context);
            ProcessUrlAttribute(SrcAttributeName, output);

            if (AppendVersion)
            {
                EnsureFileVersionProvider();

                // Retrieve the TagHelperOutput variation of the "src" attribute in case other TagHelpers in the
                // pipeline have touched the value. If the value is already encoded this ImageTagHelper may
                // not function properly.
                Src = output.Attributes[SrcAttributeName].Value as string;

                output.Attributes[SrcAttributeName] = _fileVersionProvider.AddFileVersionToPath(Src);
            }
        }
Exemplo n.º 8
0
        /// <inheritdoc />
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            string resolvedUrl;

            // Pass through attribute that is also a well-known HTML attribute.
            if (Src != null)
            {
                output.CopyHtmlAttribute(SrcAttributeName, context);
            }

            // If there's no "src" attribute in output.Attributes this will noop.
            ProcessUrlAttribute(SrcAttributeName, output);

            // Retrieve the TagHelperOutput variation of the "src" attribute in case other TagHelpers in the
            // pipeline have touched the value. If the value is already encoded this ScriptTagHelper may
            // not function properly.
            Src = output.Attributes[SrcAttributeName]?.Value as string;

            var modeResult = AttributeMatcher.DetermineMode(context, ModeDetails);

            modeResult.LogDetails(Logger, this, context.UniqueId, ViewContext.View.Path);

            if (!modeResult.FullMatches.Any())
            {
                // No attributes matched so we have nothing to do
                return;
            }

            // NOTE: Values in TagHelperOutput.Attributes may already be HTML-encoded.
            var attributes = new TagHelperAttributeList(output.Attributes);

            if (AppendVersion == true)
            {
                EnsureFileVersionProvider();

                if (Src != null)
                {
                    output.Attributes[SrcAttributeName].Value = _fileVersionProvider.AddFileVersionToPath(Src);
                }
            }

            var builder = new DefaultTagHelperContent();

            // Get the highest matched mode
            var mode = modeResult.FullMatches.Select(match => match.Mode).Max();

            if (mode == Mode.GlobbedSrc || mode == Mode.Fallback && !string.IsNullOrEmpty(SrcInclude))
            {
                BuildGlobbedScriptTags(attributes, builder);
                if (string.IsNullOrEmpty(Src))
                {
                    // Only SrcInclude is specified. Don't render the original tag.
                    output.TagName = null;
                    output.Content.SetContent(string.Empty);
                }
            }

            if (mode == Mode.Fallback)
            {
                if (TryResolveUrl(FallbackSrc, encodeWebRoot: false, resolvedUrl: out resolvedUrl))
                {
                    FallbackSrc = resolvedUrl;
                }

                BuildFallbackBlock(attributes, builder);
            }

            output.PostElement.SetContent(builder);
        }
Exemplo n.º 9
0
        /// <inheritdoc />
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            // Pass through attribute that is also a well-known HTML attribute.
            if (Href != null)
            {
                output.CopyHtmlAttribute(HrefAttributeName, context);
            }

            var modeResult = AttributeMatcher.DetermineMode(context, ModeDetails);

            var logger = Logger ?? LoggerFactory.CreateLogger<LinkTagHelper>();

            modeResult.LogDetails(logger, this, context.UniqueId, ViewContext.View.Path);

            if (!modeResult.FullMatches.Any())
            {
                // No attributes matched so we have nothing to do
                return;
            }

            // Get the highest matched mode
            var mode = modeResult.FullMatches.Select(match => match.Mode).Max();

            // NOTE: Values in TagHelperOutput.Attributes may already be HTML-encoded.
            var attributes = new Dictionary<string, object>(output.Attributes);

            var builder = new DefaultTagHelperContent();

            if (mode == Mode.Fallback && string.IsNullOrEmpty(HrefInclude) || mode == Mode.FileVersion)
            {
                // No globbing to do, just build a <link /> tag to match the original one in the source file.
                // Or just add file version to the link tag.
                BuildLinkTag(attributes, builder);
            }
            else
            {
                BuildGlobbedLinkTags(attributes, builder);
            }

            if (mode == Mode.Fallback)
            {
                BuildFallbackBlock(builder);
            }

            // We've taken over tag rendering, so prevent rendering the outer tag
            output.TagName = null;
            output.Content.SetContent(builder);
        }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (output == null)
            {
                throw new ArgumentNullException(nameof(output));
            }

            if (Src != null)
            {
                output.CopyHtmlAttribute(SrcAttributeName, context);
            }

            ProcessUrlAttribute(SrcAttributeName, output);

            Src = output.Attributes[SrcAttributeName]?.Value as string;

            var modeResult = AttributeMatcher.DetermineMode(context, ModeDetails);

            modeResult.LogDetails(Logger, this, context.UniqueId, ViewContext.View.Path);

            if (!modeResult.FullMatches.Any())
            {
                return;
            }

            if(string.IsNullOrWhiteSpace(SrcDist)
                && string.IsNullOrWhiteSpace(SrcInclude)
                && !HostingEnvironment.IsDevelopment())
            {
                return;
            }

            if(string.IsNullOrEmpty(SrcInclude)
                && HostingEnvironment.IsDevelopment())
            {
                return;
            }

            var attributes = new TagHelperAttributeList(output.Attributes);

            var builder = new DefaultTagHelperContent();
            var mode = modeResult.FullMatches.Select(match => match.Mode).Max();

            BuildGlobbedScriptTags(attributes, builder);

            if (string.IsNullOrEmpty(Src))
            {
                // Only SrcInclude is specified. Don't render the original tag.
                output.TagName = null;
                output.Content.SetContent(string.Empty);
            }

            output.PostElement.SetContent(builder);
        }