Skip to content

Commit

Permalink
Merge pull request #1727 from riganti/fix-attribute-prefixes
Browse files Browse the repository at this point in the history
Fix compilation of html attributes with prefixes
  • Loading branch information
tomasherceg authored Nov 11, 2023
2 parents a9bd0fa + 1ab04f9 commit fcc2eb8
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ private IAbstractControl ProcessObjectElement(DothtmlElementNode element, IDataC
control.ConstructorParameters = constructorParameters;

// resolve data context
var dataContextAttribute = element.Attributes.FirstOrDefault(a => a.AttributeName == "DataContext");
var dataContextAttribute = element.Attributes.FirstOrDefault(a => a.AttributeFullName == "DataContext");
if (dataContextAttribute != null)
{
ProcessAttribute(DotvvmBindableObject.DataContextProperty, dataContextAttribute, control, dataContext);
Expand All @@ -287,7 +287,7 @@ private IAbstractControl ProcessObjectElement(DothtmlElementNode element, IDataC
.AddError($"The control '{controlMetadata.Type.CSharpName}' requires a DataContext of type '{controlMetadata.DataContextConstraint.CSharpFullName}'!");
}

ProcessAttributeProperties(control, element.Attributes.Where(a => a.AttributeName != "DataContext").ToArray(), dataContext!);
ProcessAttributeProperties(control, element.Attributes.Where(a => a.AttributeFullName != "DataContext").ToArray(), dataContext!);

// process control contents
ProcessControlContent(control, element.Content);
Expand Down Expand Up @@ -324,21 +324,20 @@ public IAbstractBinding ProcessBinding(DothtmlBindingNode node, IDataContextStac
private void ProcessAttributeProperties(IAbstractControl control, DothtmlAttributeNode[] nodes, IDataContextStack dataContext)
{
var doneAttributes = new HashSet<DothtmlAttributeNode>();
string getName(DothtmlAttributeNode n) => n.AttributePrefix == null ? n.AttributeName : n.AttributePrefix + ":" + n.AttributeName;
void resolveAttribute(DothtmlAttributeNode attribute)
{
var name = getName(attribute);
var name = attribute.AttributeFullName;
if (!doneAttributes.Add(attribute)) return;

var property = controlResolver.FindProperty(control.Metadata, name, MappingMode.Attribute);
if (property == null)
{
attribute.AddError($"The control '{control.Metadata.Type}' does not have a property '{attribute.AttributeName}' and does not allow HTML attributes!");
attribute.AddError($"The control '{control.Metadata.Type}' does not have a property '{attribute.AttributeFullName}' and does not allow HTML attributes!");
}
else
{
var dependsOn = property.DataContextChangeAttributes.SelectMany(c => c.PropertyDependsOn);
foreach (var p in dependsOn.SelectMany(t => nodes.Where(n => t == getName(n))))
foreach (var p in dependsOn.SelectMany(t => nodes.Where(n => t == n.AttributeFullName)))
resolveAttribute(p);
ProcessAttribute(property, attribute, control, dataContext);
}
Expand Down Expand Up @@ -454,7 +453,7 @@ attribute.ValueNode is DothtmlValueBindingNode binding &&
{
var pGroup = groupedProperty.PropertyGroup;
var name = groupedProperty.GroupMemberName;
var prefix = attribute.AttributeName.Substring(0, attribute.AttributeName.Length - name.Length);
var prefix = attribute.AttributeFullName.Substring(0, attribute.AttributeFullName.Length - name.Length);
// If the HTML attribute is used with a prefix such as `Item`, it might be clearer if the first character is uppercased
// e.g. ItemClass reads better than Itemclass
// we supress the warning in such case
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,13 @@ public sealed class DothtmlAttributeNode : DothtmlNode
{
#region debugger display
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string debuggerDisplay
{
get
{
return (string.IsNullOrWhiteSpace(AttributePrefix) ? "" : AttributePrefix + ":") + AttributeName
+ (ValueNode == null ? "" : "=");
}
}
private string debuggerDisplay =>
AttributeFullName + (ValueNode == null ? "" : "=");
#endregion
public string? AttributePrefix => AttributePrefixNode?.Text;

public string AttributeName => AttributeNameNode.Text;
public string AttributeFullName => AttributePrefix == null ? AttributeName : AttributePrefix + ":" + AttributeName;

public DothtmlValueNode? ValueNode { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,22 @@ public void DefaultViewCompiler_DifferentControlAlternativeNames()
Assert.AreEqual(typeof(ControlWithAlternativeNames), nonLiterals[2].Metadata.Type);
Assert.AreEqual(2, nonLiterals[0].Metadata.AlternativeNames!.Count);
}

[TestMethod]
public void DefaultViewCompiler_XmlnsAttribute()
{
var root = ParseSource("""
@viewModel System.String
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 120 120" another:attribute="123"></svg>
""");
var element = root.Content.Single(c => c.Metadata.Type == typeof(HtmlGenericControl));
Assert.AreEqual("svg", element.ConstructorParameters[0]);
Assert.AreEqual("32", element.GetHtmlAttribute("width").CastTo<ResolvedPropertyValue>().Value);
Assert.AreEqual("32", element.GetHtmlAttribute("height").CastTo<ResolvedPropertyValue>().Value);
Assert.AreEqual("http://www.w3.org/2000/svg", element.GetHtmlAttribute("xmlns").CastTo<ResolvedPropertyValue>().Value);
Assert.AreEqual("http://www.w3.org/1999/xlink", element.GetHtmlAttribute("xmlns:xlink").CastTo<ResolvedPropertyValue>().Value);
Assert.AreEqual("123", element.GetHtmlAttribute("another:attribute").CastTo<ResolvedPropertyValue>().Value);
}
}

}

0 comments on commit fcc2eb8

Please sign in to comment.