/// <summary> /// Processes the attribute node. /// </summary> private void ProcessAttribute(DothtmlAttributeNode attribute, IAbstractControl control, IDataContextStack dataContext) { var name = attribute.AttributePrefix == null ? attribute.AttributeName : attribute.AttributePrefix + ":" + attribute.AttributeName; // find the property var property = controlResolver.FindProperty(control.Metadata, name); if (property != null) { if (property.IsBindingProperty || property.DataContextManipulationAttribute != null) // when DataContextManipulationAttribute is set, lets hope that author knows what is he doing. { dataContext = GetDataContextChange(dataContext, control, property); } if (!property.MarkupOptions.MappingMode.HasFlag(MappingMode.Attribute)) { attribute.AddError($"The property '{property.FullName}' cannot be used as a control attribute!"); return; } // set the property if (attribute.ValueNode == null) { // implicitly set boolean property if (property.PropertyType.IsEqualTo(new ResolvedTypeDescriptor(typeof(bool)))) { string error; if (!treeBuilder.AddProperty(control, treeBuilder.BuildPropertyValue(property, true, attribute), out error)) { attribute.AddError(error); } } else if (property.MarkupOptions.AllowAttributeWithoutValue) { string error; if (!treeBuilder.AddProperty(control, treeBuilder.BuildPropertyValue(property, (property as DotVVM.Framework.Binding.DotvvmProperty)?.DefaultValue, attribute), out error)) { attribute.AddError(error); } } else { attribute.AddError($"The attribute '{property.Name}' on the control '{control.Metadata.Type.FullName}' must have a value!"); } } else if (attribute.ValueNode is DothtmlValueBindingNode) { // binding var bindingNode = (attribute.ValueNode as DothtmlValueBindingNode).BindingNode; if (property.IsVirtual && !property.IsBindingProperty && property.PropertyType.FullName != "System.Object") { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain bindings because it's not DotvvmProperty."); } else if (!treatBindingAsHardCodedValue.Contains(bindingNode.Name)) { if (!property.MarkupOptions.AllowBinding) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain {bindingNode.Name} binding."); } } var binding = ProcessBinding(bindingNode, dataContext, property); var bindingProperty = treeBuilder.BuildPropertyBinding(property, binding, attribute); string error; if (!treeBuilder.AddProperty(control, bindingProperty, out error)) { attribute.AddError(error); } } else { // hard-coded value in markup if (!property.MarkupOptions.AllowHardCodedValue) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain hard coded value."); } var textValue = attribute.ValueNode as DothtmlValueTextNode; var value = ConvertValue(WebUtility.HtmlDecode(textValue.Text), property.PropertyType); var propertyValue = treeBuilder.BuildPropertyValue(property, value, attribute); string error; if (!treeBuilder.AddProperty(control, propertyValue, out error)) { attribute.AddError(error); } } } else { attribute.AddError($"The control '{control.Metadata.Type}' does not have a property '{attribute.AttributeName}' and does not allow HTML attributes!"); } }
/// <summary> /// Processes the attribute node. /// </summary> private void ProcessAttribute(DothtmlAttributeNode attribute, IAbstractControl control, IDataContextStack dataContext) { if (attribute.AttributePrefix == "html") { if (!control.Metadata.HasHtmlAttributesCollection) { attribute.AddError($"The control '{control.Metadata.Type.FullName}' cannot use HTML attributes!"); } else { try { treeBuilder.SetHtmlAttribute(control, ProcessAttributeValue(attribute, dataContext)); } catch (NotSupportedException ex) { if (ex.InnerException == null) { throw; } else { attribute.AddError(ex.Message); } } } return; } if (!string.IsNullOrEmpty(attribute.AttributePrefix)) { attribute.AddError("Attributes with XML namespaces are not supported!"); return; } // find the property var property = FindProperty(control.Metadata, attribute.AttributeName); if (property != null) { if (control.HasProperty(property)) { attribute.AttributeNameNode.AddError($"control '{ ((DothtmlElementNode)control.DothtmlNode).FullTagName }' already has property '{ attribute.AttributeName }'."); } if (property.IsBindingProperty || property.DataContextManipulationAttribute != null) // when DataContextManipulationAttribute is set, lets hope that author knows what is he doing. { dataContext = GetDataContextChange(dataContext, control, property); } if (!property.MarkupOptions.MappingMode.HasFlag(MappingMode.Attribute)) { attribute.AddError($"The property '{property.FullName}' cannot be used as a control attribute!"); return; } // set the property if (attribute.ValueNode == null) { attribute.AddError($"The attribute '{property.Name}' on the control '{control.Metadata.Type.FullName}' must have a value!"); } else if (attribute.ValueNode is DothtmlValueBindingNode) { // binding var bindingNode = (attribute.ValueNode as DothtmlValueBindingNode).BindingNode; if (property.IsVirtual) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain bindings because it's not DotvvmProperty."); } else if (treatBindingAsHardCodedValue.Contains(bindingNode.Name)) { if (!property.MarkupOptions.AllowHardCodedValue) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain {bindingNode.Name} binding, it can contain only hard-coded value or resource binding."); } } else { if (!property.MarkupOptions.AllowBinding) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain {bindingNode.Name} binding."); } } var binding = ProcessBinding(bindingNode, dataContext); var bindingProperty = treeBuilder.BuildPropertyBinding(property, binding, attribute); treeBuilder.SetProperty(control, bindingProperty); } else { // hard-coded value in markup if (!property.MarkupOptions.AllowHardCodedValue) { attribute.ValueNode.AddError($"The property '{ property.FullName }' cannot contain hard coded value."); } var textValue = attribute.ValueNode as DothtmlValueTextNode; var value = ConvertValue(textValue.Text, property.PropertyType); var propertyValue = treeBuilder.BuildPropertyValue(property, value, attribute); treeBuilder.SetProperty(control, propertyValue); } } else if (control.Metadata.HasHtmlAttributesCollection) { // if the property is not found, add it as an HTML attribute try { treeBuilder.SetHtmlAttribute(control, ProcessAttributeValue(attribute, dataContext)); } catch (NotSupportedException ex) { if (ex.InnerException == null) { throw; } else { attribute.AddError(ex.Message); } } } else { attribute.AddError($"The control '{control.Metadata.Type}' does not have a property '{attribute.AttributeName}' and does not allow HTML attributes!"); } }