Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HierarchyRepeater #1206

Merged
merged 22 commits into from
May 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f46a174
Add HierarchyRepeater (unfinished)
cafour Sep 30, 2021
3712add
(Re)implement server rendering for HierarchyRepeater
cafour Oct 15, 2021
78c1aea
Make HierarchyRepeater's client rendering work somewhat
cafour Oct 22, 2021
3fa2c03
Clean up HierarchyRepeater
cafour Oct 22, 2021
b8ae2a2
Continue work on HierarchyRepeater
cafour Nov 5, 2021
98cd9d9
Fix a warning in HierarchyRepeater
cafour Nov 5, 2021
3157dd4
Fix a compilation error in HierarchyRepeater
cafour Nov 12, 2021
219054c
Fix warnings in HierarchyRepeaterLevel
cafour Nov 12, 2021
5327b6b
Use KnockoutBindingGroup.AddValue in HierarchyRepeaterLevel
cafour Nov 27, 2021
3bbc9ae
hierarchy repeater: "Fixed" data contexts for client rendering
exyi Nov 27, 2021
49ea3e4
hierarchy repeater: fix tempkate ids in client-side repeater
exyi Nov 27, 2021
33c4a5c
hierarchyrepeater: fix server-side rendering datacontexts
exyi Nov 27, 2021
0c91f11
HierarchyRepeater: Add HtmlCapability for levels
cafour Apr 29, 2022
54ccd83
HierarchyRepeater: Move AddTemplateResource to ResourceManager/Resour…
cafour Apr 29, 2022
acd6ea3
HierarchyRepeater: Nest HierarchyRepeaterLevel inside HR
cafour Apr 29, 2022
b9097d9
hierarchy repeater: fix client id fragment
exyi Apr 29, 2022
82acd02
HierarchyRepeater: Add HierarchyRepeaterItem
cafour Apr 29, 2022
4a069a5
HierarchyRepeater: Add item HtmlCapability
cafour Apr 29, 2022
bd313d9
HierarchyRepeater: Add WrapperCapability
cafour Apr 29, 2022
bc5978c
HierarchyRepeater: Remove unnecessary code blocks
cafour Apr 29, 2022
f5fa51b
HierarchyRepeater: Remove the hopefully last redundant code block
cafour Apr 29, 2022
f91b2d3
HierarchyRepeater: Update the configuration test
cafour Apr 29, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -26,11 +26,13 @@ public class JavascriptTranslator
public static readonly CodeSymbolicParameter ParentKnockoutViewModelParameter = new ViewModelSymbolicParameter(1, "Parent", "$parent");

public static CodeSymbolicParameter GetKnockoutViewModelParameter(int parentIndex) => parentIndex switch {
< 0 => throw new ArgumentOutOfRangeException("parentIndex"),
0 => KnockoutViewModelParameter,
1 => ParentKnockoutViewModelParameter,
_ => new ViewModelSymbolicParameter(parentIndex, $"Parent{parentIndex}", null)
};
public static CodeSymbolicParameter GetKnockoutContextParameter(int parentIndex) => parentIndex switch {
< 0 => throw new ArgumentOutOfRangeException("parentIndex"),
0 => KnockoutContextParameter,
1 => ParentKnockoutContextParameter,
_ => new ContextSymbolicParameter(parentIndex, $"Parent{parentIndex}")
Expand Down
395 changes: 395 additions & 0 deletions src/Framework/Framework/Controls/HierarchyRepeater.cs

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions src/Framework/Framework/Controls/HtmlGenericControl.cs
Expand Up @@ -579,4 +579,23 @@ public sealed record HtmlCapability

public ValueOrBinding<string?> ID { get; init; }
}

[DotvvmControlCapability]
public sealed record WrapperCapability
{
/// <summary>
/// Gets or sets the name of the wrapper element.
/// </summary>
[MarkupOptions(AllowBinding = false)]
public string? WrapperTagName { get; init; }

public HtmlCapability Html { get; init; } = new HtmlCapability();

public DotvvmControl GetWrapper()
{
return string.IsNullOrEmpty(WrapperTagName)
? new PlaceHolder()
: new HtmlGenericControl(WrapperTagName, Html);
}
}
}
16 changes: 13 additions & 3 deletions src/Framework/Framework/ResourceManagement/ResourceManager.cs
Expand Up @@ -78,17 +78,27 @@ public void AddRequiredResource(string name)
/// Adds the template resource at the end of the HTML document.
/// </summary>
/// <param name="template">The rendered DOM elements.</param>
/// <param name="resourceId">The ID of the template resource.</param>
/// <returns>Resource ID</returns>
public string AddTemplateResource(string template)
public string AddTemplateResource(string template, string resourceId)
{
var resourceId = HashUtils.HashAndBase64Encode(template);
if (!requiredResources.ContainsKey(resourceId))
{
AddRequiredResource(resourceId, new TemplateResource(template));
}

return resourceId;
}

/// <summary>
/// Adds the template resource at the end of the HTML document.
/// </summary>
/// <param name="template">The rendered DOM elements.</param>
/// <returns>Resource ID</returns>
public string AddTemplateResource(string template)
{
var resourceId = HashUtils.HashAndBase64Encode(template);
return AddTemplateResource(template, resourceId);
}
/// <summary>
/// Adds the resource with unique name.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions src/Framework/Framework/ResourceManagement/ResourceUtils.cs
Expand Up @@ -19,6 +19,19 @@ public static string AddTemplateResource(this ResourceManager manager, IDotvvmRe
}
}

public static string AddTemplateResource(
this ResourceManager manager,
IDotvvmRequestContext context,
DotvvmControl control,
string resourceId)
{
using (var text = new StringWriter())
{
control.Render(new HtmlWriter(text, context), context);
return manager.AddTemplateResource(text.ToString(), resourceId);
}
}

public static string ReadToString(this ILocalResourceLocation location, IDotvvmRequestContext context)
{
using (var resourceStream = location.LoadResource(context))
Expand Down
1 change: 1 addition & 0 deletions src/Samples/Common/DotVVM.Samples.Common.csproj
Expand Up @@ -43,6 +43,7 @@
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_StringToObject.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\Nullable.dothtml" />
<None Remove="Views\ControlSamples\GridView\GridViewCellDecorators.dothtml" />
<None Remove="Views\ControlSamples\HierarchyRepeater\Basic.dothtml" />
<None Remove="Views\ControlSamples\Literal\Literal_NumberBinding.dothtml" />
<None Remove="Views\ControlSamples\MultiSelect\binded.dothtml" />
<None Remove="Views\ControlSamples\MultiSelect\hardcoded.dothtml" />
Expand Down
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotVVM.Framework.ViewModel;
using DotVVM.Samples.BasicSamples.ViewModels;

namespace DotVVM.Samples.Common.ViewModels.ControlSamples.HierarchyRepeater
{
public class BasicViewModel : SamplesViewModel
{
public List<Node> Roots { get; set; }

public List<Node> Empty { get; set; }

public override Task Load()
{
if (Context.IsPostBack)
return base.Load();

Roots = new() {
new Node {
Name = "Root",
Children = {
new Node {
Name = "-- 0",
},
new Node {
Name = "-- 1",
Children = {
new Node {
Name = "-- 1 -- 0"
}
}
},
new Node {
Name = "-- 2",
},
}
}
};
return base.Load();
}

public string GlobalLabel { get; set; } = "Test";

public void ClickNode(Node node)
{
node.ClickCount++;
}

public class Node
{
public string Name { get; set; } = string.Empty;

public int ClickCount { get; set; } = 0;

public List<Node> Children { get; set; } = new();
}
}
}

@@ -0,0 +1,61 @@
@viewModel DotVVM.Samples.Common.ViewModels.ControlSamples.HierarchyRepeater.BasicViewModel, DotVVM.Samples.Common
@masterPage Views/Samples.dotmaster

<dot:Content ContentPlaceHolderID="Main">
<h1>Basic usage of <code>HierarchyRepeater</code></h1>

<h2>Server Rendering</h2>
<dot:HierarchyRepeater DataSource="{value: Roots}"
ItemChildrenBinding="{value: Children}"
LevelWrapperTagName="ul"
LevelClass="level"
ItemWrapperTagName="li"
ItemClass="item"
RenderSettings.Mode="Server"
PostBack.Update="true">
<span RenderSettings.Mode="Client" title={value: _root.GlobalLabel}>{{value: Name}}</span>
<dot:Button Click="{command: _root.ClickNode(_this)}" Text="{value: ClickCount}" title={value: $"{_root.GlobalLabel}: {Name}"} />
</dot:HierarchyRepeater>

<h2>Client Rendering</h2>
<dot:HierarchyRepeater DataSource="{value: Roots}"
ItemChildrenBinding="{value: Children}"
LevelWrapperTagName="ul"
LevelClass="level"
ItemWrapperTagName="li"
ItemClass="item"
RenderSettings.Mode="Client">
<span title={value: _root.GlobalLabel}>{{value: Name}}</span>
<dot:Button Click="{command: _root.ClickNode(_this)}" Text="{value: ClickCount}" />
</dot:HierarchyRepeater>

<h2>No Item and Level Tags</h2>
<dot:HierarchyRepeater DataSource="{value: Roots}"
ItemChildrenBinding="{value: Children}"
RenderSettings.Mode="Client">
<p title={value: _root.GlobalLabel}>{{value: Name}}</p>
</dot:HierarchyRepeater>

<h2>Empty</h2>
<dot:HierarchyRepeater DataSource="{value: Empty}"
quigamdev marked this conversation as resolved.
Show resolved Hide resolved
ItemChildrenBinding="{value: Children}"
LevelTagName="ul"
ItemTagName="li">
<ItemTemplate>
<span title={value: _root.GlobalLabel}>{{value: Name}}</span>
</ItemTemplate>
<EmptyDataTemplate>
<strong>There are no nodes.</strong>
</EmptyDataTemplate>
</dot:HierarchyRepeater>

<h2>Repeater</h2>
<dot:Repeater DataSource="{value: Roots}">
<span>{{value: Name}}</span>
<dot:Button Click="{command: _root.ClickNode(_this)}" Text="{value: ClickCount}" />
</dot:Repeater>


<p> This should be propagated to all nodes <dot:TextBox Text={value: GlobalLabel} />
</dot:Content>

Expand Up @@ -606,6 +606,81 @@
"required": true
}
},
"DotVVM.Framework.Controls.HierarchyRepeater": {
"EmptyDataTemplate": {
"type": "DotVVM.Framework.Controls.ITemplate, DotVVM.Framework",
"mappingMode": "InnerElement"
},
"ItemChildrenBinding": {
"type": "DotVVM.Framework.Binding.Expressions.IValueBinding`1[[System.Collections.Generic.IEnumerable`1[[System.Object, System.Private.CoreLib, Version=***, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=***, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], DotVVM.Framework",
"dataContextChange": [
{
"$type": "DotVVM.Framework.Binding.CollectionElementDataContextChangeAttribute, DotVVM.Framework",
"Order": 1,
"TypeId": "DotVVM.Framework.Binding.CollectionElementDataContextChangeAttribute, DotVVM.Framework"
},
{
"$type": "DotVVM.Framework.Binding.ControlPropertyBindingDataContextChangeAttribute, DotVVM.Framework",
"PropertyName": "DataSource",
"PropertyDependsOn": [
"DataSource"
],
"TypeId": "DotVVM.Framework.Binding.ControlPropertyBindingDataContextChangeAttribute, DotVVM.Framework"
}
],
"required": true
},
"ItemID": {
"type": "System.String",
"fromCapability": "ItemHtmlCapability"
},
"ItemTemplate": {
"type": "DotVVM.Framework.Controls.ITemplate, DotVVM.Framework",
"dataContextChange": [
{
"$type": "DotVVM.Framework.Binding.CollectionElementDataContextChangeAttribute, DotVVM.Framework",
"Order": 1,
"TypeId": "DotVVM.Framework.Binding.CollectionElementDataContextChangeAttribute, DotVVM.Framework"
},
{
"$type": "DotVVM.Framework.Binding.ControlPropertyBindingDataContextChangeAttribute, DotVVM.Framework",
"PropertyName": "DataSource",
"PropertyDependsOn": [
"DataSource"
],
"TypeId": "DotVVM.Framework.Binding.ControlPropertyBindingDataContextChangeAttribute, DotVVM.Framework"
}
],
"mappingMode": "InnerElement",
"required": true
},
"ItemVisible": {
"type": "System.Boolean",
"fromCapability": "ItemHtmlCapability"
},
"ItemWrapperTagName": {
"type": "System.String",
"fromCapability": "ItemWrapperCapability"
},
"LevelID": {
"type": "System.String",
"fromCapability": "LevelHtmlCapability"
},
"LevelVisible": {
"type": "System.Boolean",
"fromCapability": "LevelHtmlCapability"
},
"LevelWrapperTagName": {
"type": "System.String",
"fromCapability": "LevelWrapperCapability"
},
"RenderWrapperTag": {
"type": "System.Boolean"
},
"WrapperTagName": {
"type": "System.String"
}
},
"DotVVM.Framework.Controls.HtmlGenericControl": {
"InnerText": {
"type": "System.String"
Expand Down Expand Up @@ -1101,6 +1176,26 @@
"type": "DotVVM.Framework.Controls.TextOrContentCapability, DotVVM.Framework"
}
},
"DotVVM.Framework.Controls.HierarchyRepeater": {
"ItemHtmlCapability": {
"type": "DotVVM.Framework.Controls.HtmlCapability, DotVVM.Framework",
"fromCapability": "ItemWrapperCapability",
"capabilityPrefix": "Item"
},
"ItemWrapperCapability": {
"type": "DotVVM.Framework.Controls.WrapperCapability, DotVVM.Framework",
"capabilityPrefix": "Item"
},
"LevelHtmlCapability": {
"type": "DotVVM.Framework.Controls.HtmlCapability, DotVVM.Framework",
"fromCapability": "LevelWrapperCapability",
"capabilityPrefix": "Level"
},
"LevelWrapperCapability": {
"type": "DotVVM.Framework.Controls.WrapperCapability, DotVVM.Framework",
"capabilityPrefix": "Level"
}
},
"DotVVM.Framework.Controls.HtmlGenericControl": {
"HtmlCapability": {
"type": "DotVVM.Framework.Controls.HtmlCapability, DotVVM.Framework"
Expand Down Expand Up @@ -1226,6 +1321,44 @@
}
},
"propertyGroups": {
"DotVVM.Framework.Controls.HierarchyRepeater": {
"ItemAttributes": {
"prefixes": [
"Item",
"Itemhtml:"
],
"type": "System.Object",
"fromCapability": "ItemHtmlCapability"
},
"ItemCssClasses": {
"prefix": "ItemClass-",
"type": "System.Boolean",
"fromCapability": "ItemHtmlCapability"
},
"ItemCssStyles": {
"prefix": "ItemStyle-",
"type": "System.Object",
"fromCapability": "ItemHtmlCapability"
},
"LevelAttributes": {
"prefixes": [
"Level",
"Levelhtml:"
],
"type": "System.Object",
"fromCapability": "LevelHtmlCapability"
},
"LevelCssClasses": {
"prefix": "LevelClass-",
"type": "System.Boolean",
"fromCapability": "LevelHtmlCapability"
},
"LevelCssStyles": {
"prefix": "LevelStyle-",
"type": "System.Object",
"fromCapability": "LevelHtmlCapability"
}
},
"DotVVM.Framework.Controls.HtmlGenericControl": {
"Attributes": {
"prefixes": [
Expand Down