diff --git a/src/Framework/Framework/Controls/DotvvmBindableObjectHelper.cs b/src/Framework/Framework/Controls/DotvvmBindableObjectHelper.cs index ff9ae81dca..ca30fe0fe1 100644 --- a/src/Framework/Framework/Controls/DotvvmBindableObjectHelper.cs +++ b/src/Framework/Framework/Controls/DotvvmBindableObjectHelper.cs @@ -130,7 +130,7 @@ public static TControl SetAttribute(this TControl control, string attr if (value is not null) { - control.Attributes[attribute] = value; + control.Attributes.Set(attribute, value); } else { @@ -153,6 +153,62 @@ public static TControl SetAttribute(this TControl control, str return SetAttribute(control, attribute, value?.UnwrapToObject()); } + /// Appends a value into the specified html attribute. If the attribute already exists, the old and new values are merged. Returns for fluent API usage. + public static TControl AddAttribute(this TControl control, string attribute, object? value) + where TControl : IControlWithHtmlAttributes + { + if (value is not null) + control.Attributes.Add(attribute, value); + return control; + } + /// Appends a value into the specified html attribute. If the attribute already exists, the old and new values are merged. Returns for fluent API usage. + public static TControl AddAttribute(this TControl control, string attribute, ValueOrBinding? value) + where TControl : IControlWithHtmlAttributes + { + return AddAttribute(control, attribute, value?.UnwrapToObject()); + } + + /// Appends a list of css attributes to the control. If the attributes already exist, the old and new values are merged. Returns for fluent API usage. + public static TControl AddAttributes(this TControl control, IEnumerable> attributes) + where TControl : IControlWithHtmlAttributes + { + foreach (var a in attributes) + AddAttribute(control, a.Key, a.Value); + return control; + } + + /// Appends a list of css attributes to the control. If the attributes already exist, the old and new values are merged. Returns for fluent API usage. + public static TControl AddAttributes(this TControl control, VirtualPropertyGroupDictionary attributes) + where TControl : IControlWithHtmlAttributes + { + foreach (var a in attributes.RawValues) + AddAttribute(control, a.Key, a.Value); + return control; + } + + /// Appends a css class to this control. Note that it is currently not supported if multiple bindings would have to be joined together. Returns for fluent API usage. + public static TControl AddCssClass(this TControl control, ValueOrBinding className) + where TControl : IControlWithHtmlAttributes + { + return AddAttribute(control, "class", className.UnwrapToObject()); + } + + /// Appends a list of css classes to this control. Returns for fluent API usage. + public static TControl AddCssClasses(this TControl control, params string[] classes) + where TControl : IControlWithHtmlAttributes + { + if (classes is null || classes.Length == 0) + return control; + return AddCssClass(control, string.Join(" ", classes)); + } + + /// Adds a css inline style - the `style` attribute. Returns for fluent API usage. + public static TControl AddCssStyle(this TControl control, string name, string styleValue) + where TControl : IControlWithHtmlAttributes + { + return AddAttribute(control, "style", name + ":" + styleValue); + } + /// Sets all properties from the capability into this control. If the control does not support the capability, exception is thrown. Returns for fluent API usage. public static TControl SetCapability(this TControl control, [AllowNull] TCapability capability, string prefix = "") where TControl: DotvvmBindableObject diff --git a/src/Framework/Framework/Controls/DotvvmControl.cs b/src/Framework/Framework/Controls/DotvvmControl.cs index 6b623a421d..d4bd7edc68 100644 --- a/src/Framework/Framework/Controls/DotvvmControl.cs +++ b/src/Framework/Framework/Controls/DotvvmControl.cs @@ -206,7 +206,7 @@ protected void AddDotvvmUniqueIdAttribute() { throw new DotvvmControlException(this, "Postback.Update can not be set on property which don't render html attributes."); } - htmlAttributes.Attributes["data-dotvvm-id"] = GetDotvvmUniqueId(); + htmlAttributes.Attributes.Set("data-dotvvm-id", GetDotvvmUniqueId()); } protected struct RenderState diff --git a/src/Framework/Framework/Controls/HtmlGenericControl.cs b/src/Framework/Framework/Controls/HtmlGenericControl.cs index ad4bb4ccd8..38d11f7fb5 100644 --- a/src/Framework/Framework/Controls/HtmlGenericControl.cs +++ b/src/Framework/Framework/Controls/HtmlGenericControl.cs @@ -140,8 +140,6 @@ public HtmlCapability HtmlCapability /// protected virtual bool RendersHtmlTag => TagName is object; - IDictionary IControlWithHtmlAttributes.Attributes => this.Attributes; - protected new struct RenderState { public object? Visible; diff --git a/src/Framework/Framework/Controls/IControlWithHtmlAttributes.cs b/src/Framework/Framework/Controls/IControlWithHtmlAttributes.cs index df06e4205a..89812849be 100644 --- a/src/Framework/Framework/Controls/IControlWithHtmlAttributes.cs +++ b/src/Framework/Framework/Controls/IControlWithHtmlAttributes.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using DotVVM.Framework.Binding; namespace DotVVM.Framework.Controls { @@ -9,8 +10,6 @@ namespace DotVVM.Framework.Controls /// public interface IControlWithHtmlAttributes { - - IDictionary Attributes { get; } - + VirtualPropertyGroupDictionary Attributes { get; } } } diff --git a/src/Tests/ControlTests/CompositeControlTests.cs b/src/Tests/ControlTests/CompositeControlTests.cs index 2e14eb9739..0f21dc1268 100644 --- a/src/Tests/ControlTests/CompositeControlTests.cs +++ b/src/Tests/ControlTests/CompositeControlTests.cs @@ -192,7 +192,7 @@ public static DotvvmControl GetContents( string additionalCssClass = "my-repeated-button" ) { - var r = new Repeater() { + return new Repeater() { RenderAsNamedTemplate = false, WrapperTagName = wrapperTagName, ItemTemplate = new DelegateTemplate(_ => @@ -203,10 +203,8 @@ public static DotvvmControl GetContents( ) } .SetProperty(Repeater.DataSourceProperty, dataSource) - .SetCapability(html); - - r.Attributes.Add("class", additionalCssClass); - return r; + .SetCapability(html) + .AddCssClass(additionalCssClass); } }