Skip to content

Commit

Permalink
Unify ItemsControl.GetPathFragment and SimplePathExpressionBindingPro…
Browse files Browse the repository at this point in the history
…perty
  • Loading branch information
exyi committed Feb 8, 2025
1 parent 73e4284 commit b3e27e5
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,31 @@ public KnockoutJsExpressionBindingProperty CompileToJavascript(CastedExpressionB
javascriptTranslator.CompileToJavascript(expression.Expression, dataContext).ApplyAction(a => a.Freeze()));
}

public SimplePathExpressionBindingProperty FormatSimplePath(KnockoutJsExpressionBindingProperty expression)
public SimplePathExpressionBindingProperty FormatSimplePath(IBinding binding)
{
// if contains api parameter, can't use this as a path
if (expression.Expression.DescendantNodes().Any(n => n.TryGetAnnotation(out ViewModelInfoAnnotation? vmInfo) && vmInfo.ExtensionParameter is RestApiRegistrationHelpers.ApiExtensionParameter apiParameter))
throw new Exception($"Can't get a path expression for command binding from binding that is using rest api.");
return new SimplePathExpressionBindingProperty(expression.Expression.FormatParametrizedScript());
if (binding.GetProperty<KnockoutJsExpressionBindingProperty>(ErrorHandlingMode.ReturnNull) is { } js)
{
// if contains api parameter, can't use this as a path
if (js.Expression.DescendantNodes().Any(n => n.TryGetAnnotation(out ViewModelInfoAnnotation? vmInfo) && vmInfo.ExtensionParameter is RestApiRegistrationHelpers.ApiExtensionParameter apiParameter))
throw new Exception($"Can't get a path expression for command binding from binding that is using rest api.");
return new(js.Expression.FormatParametrizedScript());
}
else if (binding.GetProperty<KnockoutExpressionBindingProperty>(ErrorHandlingMode.ReturnNull) is { } expr)
{
return new(expr.UnwrappedCode);
}
else if (binding.GetProperty<OriginalStringBindingProperty>(ErrorHandlingMode.ReturnNull) is { } originalString)
{
return new(new ParametrizedCode(originalString.Code));
}
else if (binding.GetProperty<ParsedExpressionBindingProperty>(ErrorHandlingMode.ReturnNull) is { } parsedExpression)
{
return new(new ParametrizedCode(parsedExpression.Expression.ToCSharpString()));
}
else
{
throw new Exception($"Can't create path fragment from binding {binding}, it does not have OriginalString, ParsedExpression, nor KnockoutExpression property.");
}
}

public KnockoutExpressionBindingProperty FormatJavascript(KnockoutJsExpressionBindingProperty expression)
Expand Down
12 changes: 2 additions & 10 deletions src/Framework/Framework/Controls/ItemsControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public abstract class ItemsControl : HtmlGenericControl
[MarkupOptions(AllowHardCodedValue = false, AllowResourceBinding = true)]
[BindingCompilationRequirements(
required: new[] { typeof(DataSourceAccessBinding) },
optional: new[] { typeof(DataSourceLengthBinding), typeof(CollectionElementDataContextBindingProperty) })]
optional: new[] { typeof(DataSourceLengthBinding), typeof(CollectionElementDataContextBindingProperty), typeof(SimplePathExpressionBindingProperty) })]
public object? DataSource
{
get { return GetValue(DataSourceProperty); }
Expand Down Expand Up @@ -87,15 +87,7 @@ protected IStaticValueBinding GetForeachDataBindExpression() =>
protected string GetPathFragmentExpression()
{
var binding = GetDataSourceBinding();
var stringified =
binding.GetProperty<OriginalStringBindingProperty>(ErrorHandlingMode.ReturnNull)?.Code.Trim() ??
binding.GetProperty<KnockoutExpressionBindingProperty>(ErrorHandlingMode.ReturnNull)?.Code.FormatKnockoutScript(this, binding) ??
binding.GetProperty<ParsedExpressionBindingProperty>(ErrorHandlingMode.ReturnNull)?.Expression.ToCSharpString();

if (stringified is null)
throw new DotvvmControlException(this, $"Can't create path fragment from binding {binding}, it does not have OriginalString, ParsedExpression, nor KnockoutExpression property.");

return stringified;
return binding.GetProperty<SimplePathExpressionBindingProperty>().Code.FormatKnockoutScript(this, binding);
}

/// <summary> Returns data context which is expected in the ItemTemplate </summary>
Expand Down
21 changes: 11 additions & 10 deletions src/Framework/Framework/Controls/Repeater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,13 @@ private DotvvmControl CreateEmptyItem(IDotvvmRequestContext context, IStaticVal
}

private readonly Dictionary<object, DataItemContainer> childrenCache = new(ReferenceEqualityComparer<object>.Instance);
private DotvvmControl AddItem(IList<DotvvmControl> c, IDotvvmRequestContext context, object? item = null, int? index = null, bool serverOnly = false, bool allowMemoizationRetrieve = false, bool allowMemoizationStore = false)
private DotvvmControl AddItem(IList<DotvvmControl> c, IDotvvmRequestContext context, string pathFragment, object? item = null, int? index = null, bool serverOnly = false, bool allowMemoizationRetrieve = false, bool allowMemoizationStore = false)
{
if (allowMemoizationRetrieve && item != null && childrenCache.TryGetValue(item, out var container2) && container2.Parent == null)
{
Debug.Assert(item == container2.GetValueRaw(DataContextProperty));
c.Add(container2);
SetUpServerItem(context, item, (int)index!, serverOnly, container2);
SetUpServerItem(context, item, (int)index!, serverOnly, pathFragment, container2);
return container2;
}

Expand All @@ -268,11 +268,11 @@ private DotvvmControl AddItem(IList<DotvvmControl> c, IDotvvmRequestContext cont
if (item == null && index == null)
{
Debug.Assert(!serverOnly);
SetUpClientItem(context, container);
SetUpClientItem(context, pathFragment, container);
}
else
{
SetUpServerItem(context, item!, (int)index!, serverOnly, container);
SetUpServerItem(context, item!, (int)index!, serverOnly, pathFragment, container);
}

ItemTemplate.BuildContent(context, container);
Expand Down Expand Up @@ -314,6 +314,7 @@ private void SetChildren(IDotvvmRequestContext context, bool renderClientTemplat
var dataSource = GetIEnumerableFromDataSource();
var dataSourceBinding = GetDataSourceBinding();
var serverOnly = dataSourceBinding is not IValueBinding;
var pathFragment = GetPathFragmentExpression();

if (dataSource != null)
{
Expand All @@ -325,7 +326,7 @@ private void SetChildren(IDotvvmRequestContext context, bool renderClientTemplat
{
AddSeparator(Children, context);
}
AddItem(Children, context, item, index, serverOnly,
AddItem(Children, context, pathFragment, item, index, serverOnly,
allowMemoizationRetrieve: isCommand && !memoizeReferences,
allowMemoizationStore: memoizeReferences
);
Expand All @@ -340,7 +341,7 @@ private void SetChildren(IDotvvmRequestContext context, bool renderClientTemplat
clientSeparator = AddSeparator(Children, context);
}

clientSideTemplate = AddItem(Children, context);
clientSideTemplate = AddItem(Children, context, pathFragment);
}

if (EmptyDataTemplate != null)
Expand All @@ -349,20 +350,20 @@ private void SetChildren(IDotvvmRequestContext context, bool renderClientTemplat
}
}

private void SetUpClientItem(IDotvvmRequestContext context, DataItemContainer container)
private void SetUpClientItem(IDotvvmRequestContext context, string pathFragment, DataItemContainer container)
{
container.DataContext = null;
container.SetValue(Internal.PathFragmentProperty, GetPathFragmentExpression() + "/[$index]");
container.SetValue(Internal.PathFragmentProperty, pathFragment + "/[$index]");
container.SetValue(Internal.ClientIDFragmentProperty, this.GetIndexBinding(context));
}

private void SetUpServerItem(IDotvvmRequestContext context, object item, int index, bool serverOnly, DataItemContainer container)
private void SetUpServerItem(IDotvvmRequestContext context, object item, int index, bool serverOnly, string pathFragment, DataItemContainer container)
{
container.DataItemIndex = index;
container.DataContext = item;
container.RenderItemBinding = !serverOnly;
container.SetValue(Internal.IsServerOnlyDataContextProperty, serverOnly);
container.SetValue(Internal.PathFragmentProperty, GetPathFragmentExpression() + "/[" + index + "]");
container.SetValue(Internal.PathFragmentProperty, pathFragment + "/[" + index + "]");
container.ID = index.ToString();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<!-- ko foreach: { data: Customers()?.PagingOptions()?.NearPageIndexes } -->
<li data-bind="css: { active: $data == $parent.Customers()?.PagingOptions()?.PageIndex() }">
<!-- ko if: $data != $parent.Customers()?.PagingOptions()?.PageIndex() -->
<a data-bind="text: $data + 1" href="javascript:;" onclick="dotvvm.postBack(this,[&quot;Customers()?.PagingOptions()?.NearPageIndexes/[$index]&quot;],&quot;J4s1chtqLBUO+Bt2&quot;,&quot;&quot;,null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;"></a>
<a data-bind="text: $data + 1" href="javascript:;" onclick="dotvvm.postBack(this,[&quot;Customers.PagingOptions.NearPageIndexes/[$index]&quot;],&quot;J4s1chtqLBUO+Bt2&quot;,&quot;&quot;,null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;"></a>
<!-- /ko -->
<!-- ko if: $data == $parent.Customers()?.PagingOptions()?.PageIndex() -->
<span data-bind="text: $data + 1"></span>
Expand Down

0 comments on commit b3e27e5

Please sign in to comment.