Enable `CopyHtmlAttribute` to maintain copied attribute order.
- Updated implementation to do a best guess at copying an attribute back into `TagHelperOutput.Attributes`. - Updated existing functional and unit tests to account for maintained attribute order. - Added a set of complex order based unit tests to validate `CopyHtmlAttribute` properly maintains order. #2639
This commit is contained in:
parent
405d105bd7
commit
f1eefdb650
|
|
@ -23,9 +23,17 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
/// <param name="tagHelperOutput">The <see cref="TagHelperOutput"/> this method extends.</param>
|
||||
/// <param name="attributeName">The name of the bound attribute.</param>
|
||||
/// <param name="context">The <see cref="TagHelperContext"/>.</param>
|
||||
/// <remarks>Only copies the attribute if <paramref name="tagHelperOutput"/>'s
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Only copies the attribute if <paramref name="tagHelperOutput"/>'s
|
||||
/// <see cref="TagHelperOutput.Attributes"/> does not contain an attribute with the given
|
||||
/// <paramref name="attributeName"/>.</remarks>
|
||||
/// <paramref name="attributeName"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Duplicate attributes same name in <paramref name="context"/>'s <see cref="TagHelperContext.AllAttributes"/>
|
||||
/// or <paramref name="tagHelperOutput"/>'s <see cref="TagHelperOutput.Attributes"/> may result in copied
|
||||
/// attribute order not being maintained.
|
||||
/// </para></remarks>
|
||||
public static void CopyHtmlAttribute(
|
||||
[NotNull] this TagHelperOutput tagHelperOutput,
|
||||
[NotNull] string attributeName,
|
||||
|
|
@ -33,21 +41,30 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
if (!tagHelperOutput.Attributes.ContainsName(attributeName))
|
||||
{
|
||||
IEnumerable<IReadOnlyTagHelperAttribute> entries;
|
||||
var copiedAttribute = false;
|
||||
|
||||
// We look for the original attribute so we can restore the exact attribute name the user typed.
|
||||
// Approach also ignores changes made to tagHelperOutput[attributeName].
|
||||
if (!context.AllAttributes.TryGetAttributes(attributeName, out entries))
|
||||
// We iterate context.AllAttributes backwards since we prioritize TagHelperOutput values occurring
|
||||
// before the current context.AllAttribtes[i].
|
||||
for (var i = context.AllAttributes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
// We look for the original attribute so we can restore the exact attribute name the user typed in
|
||||
// approximately the same position where the user wrote it in the Razor source.
|
||||
if (string.Equals(
|
||||
attributeName,
|
||||
context.AllAttributes[i].Name,
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
CopyHtmlAttribute(i, tagHelperOutput, context);
|
||||
copiedAttribute = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!copiedAttribute)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
Resources.FormatTagHelperOutput_AttributeDoesNotExist(attributeName, nameof(TagHelperContext)),
|
||||
nameof(attributeName));
|
||||
}
|
||||
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
tagHelperOutput.Attributes.Add(entry.Name, entry.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,5 +117,61 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
tagHelperOutput.Attributes.Remove(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CopyHtmlAttribute(
|
||||
int allAttributeIndex,
|
||||
TagHelperOutput tagHelperOutput,
|
||||
TagHelperContext context)
|
||||
{
|
||||
var existingAttribute = context.AllAttributes[allAttributeIndex];
|
||||
var copiedAttribute = new TagHelperAttribute
|
||||
{
|
||||
Name = existingAttribute.Name,
|
||||
Value = existingAttribute.Value,
|
||||
Minimized = existingAttribute.Minimized
|
||||
};
|
||||
|
||||
// Move backwards through context.AllAttributes from the provided index until we find a familiar attribute
|
||||
// in tagHelperOutput where we can insert the copied value after the familiar one.
|
||||
for (var i = allAttributeIndex - 1; i >= 0; i--)
|
||||
{
|
||||
var previousName = context.AllAttributes[i].Name;
|
||||
var index = IndexOfFirstMatch(previousName, tagHelperOutput.Attributes);
|
||||
if (index != -1)
|
||||
{
|
||||
tagHelperOutput.Attributes.Insert(index + 1, copiedAttribute);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Move forward through context.AllAttributes from the provided index until we find a familiar attribute in
|
||||
// tagHelperOutput where we can insert the copied value.
|
||||
for (var i = allAttributeIndex + 1; i < context.AllAttributes.Count; i++)
|
||||
{
|
||||
var nextName = context.AllAttributes[i].Name;
|
||||
var index = IndexOfFirstMatch(nextName, tagHelperOutput.Attributes);
|
||||
if (index != -1)
|
||||
{
|
||||
tagHelperOutput.Attributes.Insert(index, copiedAttribute);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Couldn't determine the attribute's location, add it to the end.
|
||||
tagHelperOutput.Attributes.Add(copiedAttribute);
|
||||
}
|
||||
|
||||
private static int IndexOfFirstMatch(string name, TagHelperAttributeList attributes)
|
||||
{
|
||||
for (var i = 0; i < attributes.Count; i++)
|
||||
{
|
||||
if (string.Equals(name, attributes[i].Name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
<form action="/Customer/HtmlGeneration_Customer" method="post">
|
||||
<div>
|
||||
<label class="order" for="Number">Number</label>
|
||||
<input class="form-control input-validation-error" type="number" data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." id="Number" name="Number" value="" />
|
||||
<input type="number" class="form-control input-validation-error" data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." id="Number" name="Number" value="" />
|
||||
<span class="field-validation-error" data-valmsg-for="Number" data-valmsg-replace="true">The value '' is invalid.</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="order" for="Password">Password</label>
|
||||
<input class="form-control input-validation-error" type="password" data-val="true" data-val-required="The Password field is required." id="Password" name="Password" />
|
||||
<input type="password" class="form-control input-validation-error" data-val="true" data-val-required="The Password field is required." id="Password" name="Password" />
|
||||
<span class="field-validation-error" data-valmsg-for="Password" data-valmsg-replace="true">The Password field is required.</span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<body>
|
||||
<form action="/HtmlGeneration_Home/CreateWarehouse" method="post"> <div>
|
||||
<label class="warehouse" for="City">City</label>
|
||||
<input size="50" type="text" data-val="true" data-val-minlength="The field City must be a string or array type with a minimum length of '2'." data-val-minlength-min="2" id="City" name="City" value="" />
|
||||
<input type="text" size="50" data-val="true" data-val-minlength="The field City must be a string or array type with a minimum length of '2'." data-val-minlength-min="2" id="City" name="City" value="" />
|
||||
<span class="field-validation-valid" data-valmsg-for="City" data-valmsg-replace="true"></span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<form action="/Customer/HtmlGeneration_Customer" method="post">
|
||||
<div>
|
||||
<label class="order" for="Number">Number</label>
|
||||
<input class="form-control" type="number" data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." id="Number" name="Number" value="" />
|
||||
<input type="number" class="form-control" data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." id="Number" name="Number" value="" />
|
||||
<span class="field-validation-valid" data-valmsg-for="Number" data-valmsg-replace="true"></span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="order" for="Password">Password</label>
|
||||
<input class="form-control" type="password" data-val="true" data-val-required="The Password field is required." id="Password" name="Password" />
|
||||
<input type="password" class="form-control" data-val="true" data-val-required="The Password field is required." id="Password" name="Password" />
|
||||
<span class="field-validation-valid" data-valmsg-for="Password" data-valmsg-replace="true"></span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<div>
|
||||
<label for="z0__Number">Number</label>
|
||||
<input data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." disabled="disabled" id="z0__Number" name="[0].Number" readonly="readonly" type="text" value="0" />
|
||||
<input class="form-control" type="number" id="z0__Number" name="[0].Number" value="0" />
|
||||
<input type="number" class="form-control" id="z0__Number" name="[0].Number" value="0" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="employee" for="z0__Name">Name</label>
|
||||
|
|
@ -37,7 +37,7 @@ EmployeeName_0</textarea>
|
|||
<div>
|
||||
<label for="z1__Number">Number</label>
|
||||
<input data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." disabled="disabled" id="z1__Number" name="[1].Number" readonly="readonly" type="text" value="1" />
|
||||
<input class="form-control" type="number" id="z1__Number" name="[1].Number" value="1" />
|
||||
<input type="number" class="form-control" id="z1__Number" name="[1].Number" value="1" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="employee" for="z1__Name">Name</label>
|
||||
|
|
@ -70,7 +70,7 @@ EmployeeName_1</textarea>
|
|||
<div>
|
||||
<label for="z2__Number">Number</label>
|
||||
<input data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." disabled="disabled" id="z2__Number" name="[2].Number" readonly="readonly" type="text" value="2" />
|
||||
<input class="form-control" type="number" id="z2__Number" name="[2].Number" value="2" />
|
||||
<input type="number" class="form-control" id="z2__Number" name="[2].Number" value="2" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="employee" for="z2__Name">Name</label>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<img alt="Red versioned" title="Red versioned" src="/images/red.png?v=W2F5D366_nQ2fQqUk3URdgWy2ZekXjHzHJaY5yaiOOk" />
|
||||
|
||||
<!-- Plain image tag with file version set to false -->
|
||||
<img alt="Red explicitly not versioned" title="Red versioned" src="/images/red.png">
|
||||
<img src="/images/red.png" alt="Red explicitly not versioned" title="Red versioned">
|
||||
|
||||
<!-- Plain image tag with absolute path and file version -->
|
||||
<img alt="Absolute path versioned" src="http://contoso.com/hello/world">
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<link rel="stylesheet">
|
||||
|
||||
<!-- Globbed link tag missing include but with static href -->
|
||||
<link rel="stylesheet" href="HtmlEncode[[/site.css]]" />
|
||||
<link href="HtmlEncode[[/site.css]]" rel="stylesheet" />
|
||||
|
||||
<!-- Globbed link tag with missing file -->
|
||||
|
||||
|
|
@ -32,13 +32,13 @@
|
|||
|
||||
|
||||
<!-- Globbed link tag with existing file and static href -->
|
||||
<link rel="stylesheet" href="HtmlEncode[[/site.css]]" /><link rel="stylesheet" href="HtmlEncode[[/sub/site2.css]]" />
|
||||
<link href="HtmlEncode[[/site.css]]" rel="stylesheet" /><link href="HtmlEncode[[/sub/site2.css]]" rel="stylesheet" />
|
||||
|
||||
<!-- Globbed link tag with existing file and static href should dedupe -->
|
||||
<link rel="stylesheet" href="HtmlEncode[[/site.css]]" />
|
||||
<link href="HtmlEncode[[/site.css]]" rel="stylesheet" />
|
||||
|
||||
<!-- Fallback to static href -->
|
||||
<link rel="stylesheet" data-extra="test" title=""the" title" href="HtmlEncode[[/site.min.css?a=b&c=d]]" />
|
||||
<link href="HtmlEncode[[/site.min.css?a=b&c=d]]" rel="stylesheet" data-extra="test" title=""the" title" />
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css?a=b&c=d]]"]);</script>
|
||||
|
||||
<!-- Fallback from globbed href to static href -->
|
||||
|
|
@ -50,11 +50,11 @@
|
|||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]"]);</script>
|
||||
|
||||
<!-- Fallback from globbed and static href to static href -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[site.min.css]]" /><link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.css]]" />
|
||||
<link href="HtmlEncode[[site.min.css]]" rel="stylesheet" data-extra="test" /><link href="HtmlEncode[[/site.css]]" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]"]);</script>
|
||||
|
||||
<!-- Fallback from globbed and static href with exclude to static href -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[site.min.css]]" />
|
||||
<link href="HtmlEncode[[site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]"]);</script>
|
||||
|
||||
<!-- Fallback to static href with no primary href -->
|
||||
|
|
@ -62,19 +62,19 @@
|
|||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]"]);</script>
|
||||
|
||||
<!-- Fallback to globbed href -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]" />
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]"]);</script>
|
||||
|
||||
<!-- Fallback to static and globbed href -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]" />
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]","JavaScriptEncode[[/sub/site2.css]]"]);</script>
|
||||
|
||||
<!-- Fallback to static and globbed href should dedupe -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]" />
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]"]);</script>
|
||||
|
||||
<!-- Fallback to static and globbed href with exclude -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]" />
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]","JavaScriptEncode[[/sub/site2.css]]"]);</script>
|
||||
|
||||
<!-- Fallback from globbed href to glbobed href -->
|
||||
|
|
@ -86,44 +86,44 @@
|
|||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]"]);</script>
|
||||
|
||||
<!-- Fallback from globbed and static href to globbed href -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[site.min.css]]" /><link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.css]]" />
|
||||
<link href="HtmlEncode[[site.min.css]]" rel="stylesheet" data-extra="test" /><link href="HtmlEncode[[/site.css]]" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]"]);</script>
|
||||
|
||||
<!-- Fallback from globbed and static href with exclude to globbed href -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[site.min.css]]">
|
||||
<link href="HtmlEncode[[site.min.css]]" rel="stylesheet" data-extra="test">
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]"]);</script>
|
||||
|
||||
<!-- Kitchen sink, all the attributes -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[site.min.css]]" />
|
||||
<link href="HtmlEncode[[site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css]]","JavaScriptEncode[[/sub/site2.css]]"]);</script>
|
||||
|
||||
<!-- Fallback to globbed href that doesn't exist -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]" />
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Fallback to globbed href outside webroot -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]" />
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Fallback with missing attribute -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]" />
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Fallback with missing attribute -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]" />
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Fallback with missing attribute -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]" />
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Plain link tag with file version -->
|
||||
<link rel="stylesheet" href="HtmlEncode[[/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc]]" />
|
||||
<link href="HtmlEncode[[/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc]]" rel="stylesheet" />
|
||||
|
||||
<!-- Globbed link tag with existing file and file version -->
|
||||
<link rel="stylesheet" href="HtmlEncode[[/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc]]" />
|
||||
|
||||
<!-- Fallback with file version -->
|
||||
<link rel="stylesheet" data-extra="test" href="HtmlEncode[[/site.min.css]]">
|
||||
<link href="HtmlEncode[[/site.min.css]]" rel="stylesheet" data-extra="test">
|
||||
<meta name="x-stylesheet-fallback-test" class="HtmlEncode[[hidden]]" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("JavaScriptEncode[[visibility]]","JavaScriptEncode[[hidden]]",["JavaScriptEncode[[/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc]]"]);</script>
|
||||
|
||||
<!-- Globbed link tag with existing file, static href and file version -->
|
||||
<link rel="stylesheet" href="HtmlEncode[[/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc]]" /><link rel="stylesheet" href="HtmlEncode[[/sub/site2.css?v=30cxPex0tA9xEatW7f1Qhnn8tVLAHgE6xwIZhESq0y0]]" /><link rel="stylesheet" href="HtmlEncode[[/sub/site3.css?v=fSxxOr1Q4Dq2uPuzlju5UYGuK0SKABI-ghvaIGEsZDc]]" /><link rel="stylesheet" href="HtmlEncode[[/sub/site3.min.css?v=s8JMmAZxBn0dzuhRtQ0wgOvNBK4XRJRWEC2wfzsVF9M]]" />
|
||||
<link href="HtmlEncode[[/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc]]" rel="stylesheet" /><link href="HtmlEncode[[/sub/site2.css?v=30cxPex0tA9xEatW7f1Qhnn8tVLAHgE6xwIZhESq0y0]]" rel="stylesheet" /><link href="HtmlEncode[[/sub/site3.css?v=fSxxOr1Q4Dq2uPuzlju5UYGuK0SKABI-ghvaIGEsZDc]]" rel="stylesheet" /><link href="HtmlEncode[[/sub/site3.min.css?v=s8JMmAZxBn0dzuhRtQ0wgOvNBK4XRJRWEC2wfzsVF9M]]" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<link rel="stylesheet">
|
||||
|
||||
<!-- Globbed link tag missing include but with static href -->
|
||||
<link rel="stylesheet" href="/site.css" />
|
||||
<link href="/site.css" rel="stylesheet" />
|
||||
|
||||
<!-- Globbed link tag with missing file -->
|
||||
|
||||
|
|
@ -32,13 +32,13 @@
|
|||
|
||||
|
||||
<!-- Globbed link tag with existing file and static href -->
|
||||
<link rel="stylesheet" href="/site.css" /><link rel="stylesheet" href="/sub/site2.css" />
|
||||
<link href="/site.css" rel="stylesheet" /><link href="/sub/site2.css" rel="stylesheet" />
|
||||
|
||||
<!-- Globbed link tag with existing file and static href should dedupe -->
|
||||
<link rel="stylesheet" href="/site.css" />
|
||||
<link href="/site.css" rel="stylesheet" />
|
||||
|
||||
<!-- Fallback to static href -->
|
||||
<link rel="stylesheet" data-extra="test" title=""the" title" href="/site.min.css?a=b&c=d" />
|
||||
<link href="/site.min.css?a=b&c=d" rel="stylesheet" data-extra="test" title=""the" title" />
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css?a=b\u0026c=d"]);</script>
|
||||
|
||||
<!-- Fallback from globbed href to static href -->
|
||||
|
|
@ -50,11 +50,11 @@
|
|||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css"]);</script>
|
||||
|
||||
<!-- Fallback from globbed and static href to static href -->
|
||||
<link rel="stylesheet" data-extra="test" href="site.min.css" /><link rel="stylesheet" data-extra="test" href="/site.css" />
|
||||
<link href="site.min.css" rel="stylesheet" data-extra="test" /><link href="/site.css" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css"]);</script>
|
||||
|
||||
<!-- Fallback from globbed and static href with exclude to static href -->
|
||||
<link rel="stylesheet" data-extra="test" href="site.min.css" />
|
||||
<link href="site.min.css" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css"]);</script>
|
||||
|
||||
<!-- Fallback to static href with no primary href -->
|
||||
|
|
@ -62,19 +62,19 @@
|
|||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css"]);</script>
|
||||
|
||||
<!-- Fallback to globbed href -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css" />
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css"]);</script>
|
||||
|
||||
<!-- Fallback to static and globbed href -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css" />
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css","\/sub\/site2.css"]);</script>
|
||||
|
||||
<!-- Fallback to static and globbed href should dedupe -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css" />
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css"]);</script>
|
||||
|
||||
<!-- Fallback to static and globbed href with exclude -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css" />
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css","\/sub\/site2.css"]);</script>
|
||||
|
||||
<!-- Fallback from globbed href to glbobed href -->
|
||||
|
|
@ -86,44 +86,44 @@
|
|||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css"]);</script>
|
||||
|
||||
<!-- Fallback from globbed and static href to globbed href -->
|
||||
<link rel="stylesheet" data-extra="test" href="site.min.css" /><link rel="stylesheet" data-extra="test" href="/site.css" />
|
||||
<link href="site.min.css" rel="stylesheet" data-extra="test" /><link href="/site.css" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css"]);</script>
|
||||
|
||||
<!-- Fallback from globbed and static href with exclude to globbed href -->
|
||||
<link rel="stylesheet" data-extra="test" href="site.min.css">
|
||||
<link href="site.min.css" rel="stylesheet" data-extra="test">
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css"]);</script>
|
||||
|
||||
<!-- Kitchen sink, all the attributes -->
|
||||
<link rel="stylesheet" data-extra="test" href="site.min.css" />
|
||||
<link href="site.min.css" rel="stylesheet" data-extra="test" />
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css","\/sub\/site2.css"]);</script>
|
||||
|
||||
<!-- Fallback to globbed href that doesn't exist -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css" />
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Fallback to globbed href outside webroot -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css" />
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Fallback with missing attribute -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css" />
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Fallback with missing attribute -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css" />
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Fallback with missing attribute -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css" />
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test" />
|
||||
|
||||
<!-- Plain link tag with file version -->
|
||||
<link rel="stylesheet" href="/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc" />
|
||||
<link href="/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc" rel="stylesheet" />
|
||||
|
||||
<!-- Globbed link tag with existing file and file version -->
|
||||
<link rel="stylesheet" href="/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc" />
|
||||
|
||||
<!-- Fallback with file version -->
|
||||
<link rel="stylesheet" data-extra="test" href="/site.min.css">
|
||||
<link href="/site.min.css" rel="stylesheet" data-extra="test">
|
||||
<meta name="x-stylesheet-fallback-test" class="hidden" /><script>!function(a,b,c){var d,e=document,f=e.getElementsByTagName("SCRIPT"),g=f[f.length-1].previousElementSibling,h=e.defaultView&&e.defaultView.getComputedStyle?e.defaultView.getComputedStyle(g):g.currentStyle;if(h&&h[a]!==b)for(d=0;d<c.length;d++)e.write('<link rel="stylesheet" href="'+c[d]+'"/>')}("visibility","hidden",["\/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc"]);</script>
|
||||
|
||||
<!-- Globbed link tag with existing file, static href and file version -->
|
||||
<link rel="stylesheet" href="/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc" /><link rel="stylesheet" href="/sub/site2.css?v=30cxPex0tA9xEatW7f1Qhnn8tVLAHgE6xwIZhESq0y0" /><link rel="stylesheet" href="/sub/site3.css?v=fSxxOr1Q4Dq2uPuzlju5UYGuK0SKABI-ghvaIGEsZDc" /><link rel="stylesheet" href="/sub/site3.min.css?v=s8JMmAZxBn0dzuhRtQ0wgOvNBK4XRJRWEC2wfzsVF9M" />
|
||||
<link href="/site.css?v=XY7YsMemPf8AGU4SIX9ED9eOjK1LOQWu2dmCNmh-pQc" rel="stylesheet" /><link href="/sub/site2.css?v=30cxPex0tA9xEatW7f1Qhnn8tVLAHgE6xwIZhESq0y0" rel="stylesheet" /><link href="/sub/site3.css?v=fSxxOr1Q4Dq2uPuzlju5UYGuK0SKABI-ghvaIGEsZDc" rel="stylesheet" /><link href="/sub/site3.min.css?v=s8JMmAZxBn0dzuhRtQ0wgOvNBK4XRJRWEC2wfzsVF9M" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title></title>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
<form action="HtmlEncode[[/HtmlGeneration_Order/Submit]]" method="HtmlEncode[[post]]">
|
||||
<div>
|
||||
<label class="order" for="HtmlEncode[[Shipping]]">HtmlEncode[[Shipping]]</label>
|
||||
<input size="50" type="HtmlEncode[[text]]" id="HtmlEncode[[Shipping]]" name="HtmlEncode[[Shipping]]" value="HtmlEncode[[Your shipping method is UPSP]]" />
|
||||
<input type="HtmlEncode[[text]]" size="50" id="HtmlEncode[[Shipping]]" name="HtmlEncode[[Shipping]]" value="HtmlEncode[[Your shipping method is UPSP]]" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="order" for="HtmlEncode[[ShippingDateTime]]">HtmlEncode[[ShippingDateTime]]</label>
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="order" for="HtmlEncode[[Customer_Number]]">HtmlEncode[[Number]]</label>
|
||||
<input class="form-control" type="HtmlEncode[[number]]" data-val="HtmlEncode[[true]]" data-val-range="HtmlEncode[[The field Number must be between 1 and 100.]]" data-val-range-max="HtmlEncode[[100]]" data-val-range-min="HtmlEncode[[1]]" data-val-required="HtmlEncode[[The Number field is required.]]" id="HtmlEncode[[Customer_Number]]" name="HtmlEncode[[Customer.Number]]" value="HtmlEncode[[1]]" />
|
||||
<input type="HtmlEncode[[number]]" class="form-control" data-val="HtmlEncode[[true]]" data-val-range="HtmlEncode[[The field Number must be between 1 and 100.]]" data-val-range-max="HtmlEncode[[100]]" data-val-range-min="HtmlEncode[[1]]" data-val-required="HtmlEncode[[The Number field is required.]]" id="HtmlEncode[[Customer_Number]]" name="HtmlEncode[[Customer.Number]]" value="HtmlEncode[[1]]" />
|
||||
<span class="HtmlEncode[[field-validation-valid]]" data-valmsg-for="HtmlEncode[[Customer.Number]]" data-valmsg-replace="HtmlEncode[[true]]"></span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="order" for="HtmlEncode[[Customer_Password]]">HtmlEncode[[Password]]</label>
|
||||
<input class="form-control" type="HtmlEncode[[password]]" data-val="HtmlEncode[[true]]" data-val-required="HtmlEncode[[The Password field is required.]]" id="HtmlEncode[[Customer_Password]]" name="HtmlEncode[[Customer.Password]]" />
|
||||
<input type="HtmlEncode[[password]]" class="form-control" data-val="HtmlEncode[[true]]" data-val-required="HtmlEncode[[The Password field is required.]]" id="HtmlEncode[[Customer_Password]]" name="HtmlEncode[[Customer.Password]]" />
|
||||
<span class="HtmlEncode[[field-validation-valid]]" data-valmsg-for="HtmlEncode[[Customer.Password]]" data-valmsg-replace="HtmlEncode[[true]]"></span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title></title>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
<form action="/HtmlGeneration_Order/Submit" method="post">
|
||||
<div>
|
||||
<label class="order" for="Shipping">Shipping</label>
|
||||
<input size="50" type="text" id="Shipping" name="Shipping" value="Your shipping method is UPSP" />
|
||||
<input type="text" size="50" id="Shipping" name="Shipping" value="Your shipping method is UPSP" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="order" for="ShippingDateTime">ShippingDateTime</label>
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="order" for="Customer_Number">Number</label>
|
||||
<input class="form-control" type="number" data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." id="Customer_Number" name="Customer.Number" value="1" />
|
||||
<input type="number" class="form-control" data-val="true" data-val-range="The field Number must be between 1 and 100." data-val-range-max="100" data-val-range-min="1" data-val-required="The Number field is required." id="Customer_Number" name="Customer.Number" value="1" />
|
||||
<span class="field-validation-valid" data-valmsg-for="Customer.Number" data-valmsg-replace="true"></span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
</div>
|
||||
<div>
|
||||
<label class="order" for="Customer_Password">Password</label>
|
||||
<input class="form-control" type="password" data-val="true" data-val-required="The Password field is required." id="Customer_Password" name="Customer.Password" />
|
||||
<input type="password" class="form-control" data-val="true" data-val-required="The Password field is required." id="Customer_Password" name="Customer.Password" />
|
||||
<span class="field-validation-valid" data-valmsg-for="Customer.Password" data-valmsg-replace="true"></span>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title></title>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
<form method="get" action="HtmlEncode[[/HtmlGeneration_Home/ProductSubmit]]">
|
||||
<div>
|
||||
<label class="product" for="HtmlEncode[[HomePage]]">HtmlEncode[[HomePage]]</label>
|
||||
<input size="50" type="HtmlEncode[[url]]" id="HtmlEncode[[HomePage]]" name="HtmlEncode[[HomePage]]" value="HtmlEncode[[http://www.contoso.com/]]" />
|
||||
<input type="HtmlEncode[[url]]" size="50" id="HtmlEncode[[HomePage]]" name="HtmlEncode[[HomePage]]" value="HtmlEncode[[http://www.contoso.com/]]" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="HtmlEncode[[Description]]">HtmlEncode[[Description]]</label>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title></title>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
<form method="get" action="/HtmlGeneration_Home/ProductSubmit">
|
||||
<div>
|
||||
<label class="product" for="HomePage">HomePage</label>
|
||||
<input size="50" type="url" id="HomePage" name="HomePage" value="http://www.contoso.com/" />
|
||||
<input type="url" size="50" id="HomePage" name="HomePage" value="http://www.contoso.com/" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="Description">Description</label>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<form action="/HtmlGeneration_Product" method="post"> <div>
|
||||
<label class="product" for="z0__HomePage">HomePage</label>
|
||||
<input size="50" disabled="disabled" readonly="readonly" type="url" id="z0__HomePage" name="[0].HomePage" value="http://www.contoso.com/" />
|
||||
<input type="url" size="50" disabled="disabled" readonly="readonly" id="z0__HomePage" name="[0].HomePage" value="http://www.contoso.com/" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
</textarea>
|
||||
</div> <div>
|
||||
<label class="product" for="z1__HomePage">HomePage</label>
|
||||
<input size="50" disabled="disabled" readonly="readonly" type="url" id="z1__HomePage" name="[1].HomePage" value="" />
|
||||
<input type="url" size="50" disabled="disabled" readonly="readonly" id="z1__HomePage" name="[1].HomePage" value="" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
</textarea>
|
||||
</div> <div>
|
||||
<label class="product" for="z2__HomePage">HomePage</label>
|
||||
<input size="50" disabled="disabled" readonly="readonly" type="url" id="z2__HomePage" name="[2].HomePage" value="" />
|
||||
<input type="url" size="50" disabled="disabled" readonly="readonly" id="z2__HomePage" name="[2].HomePage" value="" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -10,15 +10,15 @@
|
|||
// Regular script with comment in body, and extra properties.
|
||||
</script>
|
||||
|
||||
<script data-foo="foo-data2" title="<the title>" src="HtmlEncode[[/blank.js?a=b&c=d]]">
|
||||
<script src="HtmlEncode[[/blank.js?a=b&c=d]]" data-foo="foo-data2" title="<the title>">
|
||||
// TagHelper script with comment in body, and extra properties.
|
||||
</script>
|
||||
<script>(false||document.write("<script JavaScriptEncode[[data-foo]]=\"JavaScriptEncode[[foo-data2]]\" JavaScriptEncode[[title]]=\"JavaScriptEncode[[<the title>]]\" src=\"JavaScriptEncode[[/site.js?a=b&c=d]]\"><\/script>"));</script>
|
||||
<script>(false||document.write("<script src=\"JavaScriptEncode[[/site.js?a=b&c=d]]\" JavaScriptEncode[[data-foo]]=\"JavaScriptEncode[[foo-data2]]\" JavaScriptEncode[[title]]=\"JavaScriptEncode[[<the title>]]\"><\/script>"));</script>
|
||||
|
||||
<script title=""the" title" src="HtmlEncode[[/blank.js]]">
|
||||
<script src="HtmlEncode[[/blank.js]]" title=""the" title">
|
||||
// Fallback to globbed src
|
||||
</script>
|
||||
<script>(false||document.write("<script JavaScriptEncode[[title]]=\"JavaScriptEncode[["the" title]]\" src=\"JavaScriptEncode[[/site.js]]\"><\/script>"));</script>
|
||||
<script>(false||document.write("<script src=\"JavaScriptEncode[[/site.js]]\" JavaScriptEncode[[title]]=\"JavaScriptEncode[["the" title]]\"><\/script>"));</script>
|
||||
|
||||
<script src="HtmlEncode[[/blank.js]]">
|
||||
// Fallback to globbed src with exclude
|
||||
|
|
|
|||
|
|
@ -10,15 +10,15 @@
|
|||
// Regular script with comment in body, and extra properties.
|
||||
</script>
|
||||
|
||||
<script data-foo="foo-data2" title="<the title>" src="/blank.js?a=b&c=d">
|
||||
<script src="/blank.js?a=b&c=d" data-foo="foo-data2" title="<the title>">
|
||||
// TagHelper script with comment in body, and extra properties.
|
||||
</script>
|
||||
<script>(false||document.write("<script data-foo=\"foo-data2\" title=\"\u0026lt;the title\u003E\" src=\"\/site.js?a=b\u0026c=d\"><\/script>"));</script>
|
||||
<script>(false||document.write("<script src=\"\/site.js?a=b\u0026c=d\" data-foo=\"foo-data2\" title=\"\u0026lt;the title\u003E\"><\/script>"));</script>
|
||||
|
||||
<script title=""the" title" src="/blank.js">
|
||||
<script src="/blank.js" title=""the" title">
|
||||
// Fallback to globbed src
|
||||
</script>
|
||||
<script>(false||document.write("<script title=\"\u0022the\u0022 title\" src=\"\/site.js\"><\/script>"));</script>
|
||||
<script>(false||document.write("<script src=\"\/site.js\" title=\"\u0022the\u0022 title\"><\/script>"));</script>
|
||||
|
||||
<script src="/blank.js">
|
||||
// Fallback to globbed src with exclude
|
||||
|
|
|
|||
|
|
@ -536,8 +536,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var expectedAttributes = new TagHelperAttributeList
|
||||
{
|
||||
{ "class", "form-control radio-control" },
|
||||
{ "type", inputTypeName ?? "radio" }, // Generator restores type attribute; adds "radio" if none.
|
||||
{ "value", value },
|
||||
{ "type", inputTypeName ?? "radio" }, // Generator restores type attribute; adds "radio" if none.
|
||||
};
|
||||
var expectedPreContent = "original pre-content";
|
||||
var expectedContent = "original content";
|
||||
|
|
|
|||
|
|
@ -388,8 +388,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
// Assert
|
||||
Assert.Equal("rel", output.Attributes[0].Name);
|
||||
Assert.Equal("data-extra", output.Attributes[1].Name);
|
||||
Assert.Equal("href", output.Attributes[2].Name);
|
||||
Assert.Equal("href", output.Attributes[1].Name);
|
||||
Assert.Equal("data-extra", output.Attributes[2].Name);
|
||||
}
|
||||
|
||||
public static TheoryData DoesNotRunWhenARequiredAttributeIsMissing_Data
|
||||
|
|
|
|||
|
|
@ -589,8 +589,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
// Assert
|
||||
Assert.Equal("data-extra", output.Attributes[0].Name);
|
||||
Assert.Equal("data-more", output.Attributes[1].Name);
|
||||
Assert.Equal("src", output.Attributes[2].Name);
|
||||
Assert.Equal("src", output.Attributes[1].Name);
|
||||
Assert.Equal("data-more", output.Attributes[2].Name);
|
||||
Assert.Empty(logger.Logged);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,13 +8,345 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Framework.WebEncoders.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||
{
|
||||
public class TagHelperOutputExtensionsTest
|
||||
{
|
||||
public static TheoryData CopyHtmlAttributeData_MaintainsOrder
|
||||
{
|
||||
get
|
||||
{
|
||||
// attributeNameToCopy, outputAttributes, allAttributes, expectedAttributes
|
||||
return new TheoryData<
|
||||
string,
|
||||
TagHelperAttributeList,
|
||||
TagHelperAttributeList,
|
||||
IEnumerable<TagHelperAttribute>>
|
||||
{
|
||||
{
|
||||
"first",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "second", "B" },
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "second", "B" }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("second", "B"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"second",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "second", "B" },
|
||||
{ "second", "Duplicate B" },
|
||||
{ "first", "A" },
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("second", "B"),
|
||||
new TagHelperAttribute("second", "Duplicate B"),
|
||||
new TagHelperAttribute("first", "A"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"second",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "second", "B" },
|
||||
{ "first", "A" },
|
||||
{ "second", "Duplicate B" }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("second", "B"),
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("second", "Duplicate B"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"dynamic",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "second", "B" },
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "dynamic", "value" },
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("second", "B"),
|
||||
new TagHelperAttribute("dynamic", "value"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"second",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "dynamic", "value" },
|
||||
{ "secondDynamic", "another value"}
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "second", "B" }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("dynamic", "value"),
|
||||
new TagHelperAttribute("secondDynamic", "another value"),
|
||||
new TagHelperAttribute("second", "B"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"second",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "dynamic", "value" },
|
||||
{ "secondDynamic", "another value"}
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "second", "B" }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("second", "B"),
|
||||
new TagHelperAttribute("dynamic", "value"),
|
||||
new TagHelperAttribute("secondDynamic", "another value"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"third",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "dynamic", "value" },
|
||||
{ "secondDynamic", "another value"}
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "second", "B" },
|
||||
{ "third", "C" }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("third", "C"),
|
||||
new TagHelperAttribute("dynamic", "value"),
|
||||
new TagHelperAttribute("secondDynamic", "another value"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"first",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "C" },
|
||||
{ "dynamic", "value" },
|
||||
{ "secondDynamic", "another value"}
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "second", "B" },
|
||||
{ "third", "C" }
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("third", "C"),
|
||||
new TagHelperAttribute("dynamic", "value"),
|
||||
new TagHelperAttribute("secondDynamic", "another value"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"first",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "C" },
|
||||
{ "dynamic", "value" },
|
||||
{ "secondDynamic", "another value"}
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "secondDynamic", "another value"},
|
||||
{ "second", "B" },
|
||||
{ "third", "C" },
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("third", "C"),
|
||||
new TagHelperAttribute("dynamic", "value"),
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("secondDynamic", "another value"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"first",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "C" },
|
||||
{ "dynamic", "value" },
|
||||
{ "secondDynamic", "another value"}
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "secondDynamic", "another value"},
|
||||
{ "first", "Second first" },
|
||||
{ "second", "B" },
|
||||
{ "third", "C" },
|
||||
{ "first", "third first" },
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("third", "C"),
|
||||
new TagHelperAttribute("first", "third first"),
|
||||
new TagHelperAttribute("dynamic", "value"),
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("secondDynamic", "another value"),
|
||||
new TagHelperAttribute("first", "Second first"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"first",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "C" },
|
||||
{ "third", "Duplicate Third" },
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "C" },
|
||||
{ "first", "A" },
|
||||
{ "third", "Duplicate Third" },
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("third", "C"),
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("third", "Duplicate Third"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"first",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "C" },
|
||||
{ "third", "Duplicate Third" },
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "C" },
|
||||
{ "third", "Duplicate Third" },
|
||||
{ "first", "A" },
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("third", "C"),
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("third", "Duplicate Third"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"first",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "D" },
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "first", "A" },
|
||||
{ "first", "B" },
|
||||
{ "first", "C" },
|
||||
{ "third", "D" },
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("first", "C"),
|
||||
new TagHelperAttribute("first", "B"),
|
||||
new TagHelperAttribute("third", "D"),
|
||||
}
|
||||
},
|
||||
{
|
||||
"first",
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "D" },
|
||||
{ "dynamic", "value" },
|
||||
{ "third", "Duplicate Third" },
|
||||
},
|
||||
new TagHelperAttributeList
|
||||
{
|
||||
{ "third", "D" },
|
||||
{ "first", "A" },
|
||||
{ "third", "Duplicate Third" },
|
||||
{ "first", "B" },
|
||||
{ "first", "C" },
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new TagHelperAttribute("third", "D"),
|
||||
new TagHelperAttribute("first", "A"),
|
||||
new TagHelperAttribute("first", "B"),
|
||||
new TagHelperAttribute("first", "C"),
|
||||
new TagHelperAttribute("dynamic", "value"),
|
||||
new TagHelperAttribute("third", "Duplicate Third"),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(CopyHtmlAttributeData_MaintainsOrder))]
|
||||
public void CopyHtmlAttribute_MaintainsOrder(
|
||||
string attributeNameToCopy,
|
||||
TagHelperAttributeList outputAttributes,
|
||||
TagHelperAttributeList allAttributes,
|
||||
IEnumerable<TagHelperAttribute> expectedAttributes)
|
||||
{
|
||||
// Arrange
|
||||
var output = new TagHelperOutput("p", attributes: new TagHelperAttributeList(outputAttributes));
|
||||
var context = new TagHelperContext(
|
||||
allAttributes,
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: "test",
|
||||
getChildContentAsync: useCachedResult => Task.FromResult<TagHelperContent>(result: null));
|
||||
|
||||
// Act
|
||||
output.CopyHtmlAttribute(attributeNameToCopy, context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedAttributes, output.Attributes, CaseSensitiveTagHelperAttributeComparer.Default);
|
||||
}
|
||||
|
||||
public static TheoryData CopyHtmlAttributeData_MultipleAttributesSameName
|
||||
{
|
||||
get
|
||||
|
|
|
|||
Loading…
Reference in New Issue