diff --git a/src/Framework/Framework/Compilation/Javascript/JavascriptTranslator.cs b/src/Framework/Framework/Compilation/Javascript/JavascriptTranslator.cs index 36df1249b..f90154890 100644 --- a/src/Framework/Framework/Compilation/Javascript/JavascriptTranslator.cs +++ b/src/Framework/Framework/Compilation/Javascript/JavascriptTranslator.cs @@ -261,19 +261,25 @@ public ViewModelInfoAnnotation(Type type, bool isControl, BindingExtensionParame } } + /// Specified if properties of the current object are wrapped in knockout observables or not. Observability of the current value is not specified in this annotation, but using . public sealed record JsObjectObservableMap: IEquatable { - /// The default value for all descendants, unless overriden using the other properties + /// The default value for all descendants, unless overridden using the other properties. If null, the default nullability for the current expression will be used. public bool? ContainsObservables { get; set; } /// Default value for all properties. Null means that `ContainsObservables` is assumed to be the same as the parent's public JsObjectObservableMap? DefaultChild { get; set; } + /// Observable mapping for child objects. public Dictionary? ChildObjects { get; set; } + /// Specifies if the specific property is ko.observable or not. Does not include more nested properties, that is specified in the property. public Dictionary? PropertyIsObservable { get; set; } + /// If is null, returns the default property observability. public bool? IsPropertyObservable(string? name) => name is {} && PropertyIsObservable?.TryGetValue(name, out var value) == true ? value : ContainsObservables; + + /// If objectPath[x] is null, returns the default property observability. public bool? IsPropertyObservable(ReadOnlySpan objectPath) { if (objectPath.Length == 0) return null; @@ -297,6 +303,7 @@ public JsObjectObservableMap GetChildObject(ReadOnlySpan objectPath) return current; } + /// Replaces properties in this with non-default properties in public JsObjectObservableMap OverrideWith(JsObjectObservableMap? @override) { if (@override is null || @override == Default || this == @override || this == Default) return this; diff --git a/src/Framework/Framework/Compilation/Javascript/JsViewModelPropertyAdjuster.cs b/src/Framework/Framework/Compilation/Javascript/JsViewModelPropertyAdjuster.cs index 853440385..7a540625a 100644 --- a/src/Framework/Framework/Compilation/Javascript/JsViewModelPropertyAdjuster.cs +++ b/src/Framework/Framework/Compilation/Javascript/JsViewModelPropertyAdjuster.cs @@ -178,37 +178,43 @@ public override void VisitSymbolicParameter(JsSymbolicParameter expr) } } + /// Indicates that this invocation only unwraps a knockout observable and was automatically inserted by public sealed class ObservableUnwrapInvocationAnnotation { private ObservableUnwrapInvocationAnnotation() { } public static ObservableUnwrapInvocationAnnotation Instance = new ObservableUnwrapInvocationAnnotation(); } + /// Indicates that this invocation is a knockout observable value assignment and was automatically inserted by public sealed class ObservableSetterInvocationAnnotation { private ObservableSetterInvocationAnnotation() { } public static ObservableSetterInvocationAnnotation Instance = new ObservableSetterInvocationAnnotation(); } + /// Result of the annotated expression is always a knockout observable. DotVVM will automatically unwrap the observable, unless the is also specified. public sealed class ResultIsObservableAnnotation { private ResultIsObservableAnnotation() { } public static ResultIsObservableAnnotation Instance = new ResultIsObservableAnnotation(); } + /// Result is a knockout observable array. public sealed class ResultIsObservableArrayAnnotation { private ResultIsObservableArrayAnnotation() { } public static ResultIsObservableArrayAnnotation Instance = new ResultIsObservableArrayAnnotation(); } + /// Result of the annotated expression may or may not be a knockout observable. DotVVM will automatically unwrap the observable, unless the is also specified. public sealed class ResultMayBeObservableAnnotation { private ResultMayBeObservableAnnotation() { } public static ResultMayBeObservableAnnotation Instance = new ResultMayBeObservableAnnotation(); } + /// This node should return observable - instructs the to not unwrap the node and the to not use .state in the subexpression. public sealed class ShouldBeObservableAnnotation { private ShouldBeObservableAnnotation() { } public static ShouldBeObservableAnnotation Instance = new ShouldBeObservableAnnotation(); } - /// Instruct the to process the node after it's children are resolved and before it is handled itself by the rules + /// Instruct the to process the node after it's children are resolved and before it is handled itself by the rules public sealed class ObservableTransformationAnnotation { public readonly Func TransformExpression; @@ -217,7 +223,7 @@ public ObservableTransformationAnnotation(Func trans TransformExpression = transformExpression; } - /// Makes sure that the observable is fully wrapped in observable (i.e. wraps the expression in `ko.pureComputed(...)` when needed) + /// Makes sure that the observable is fully wrapped in observable (i.e. wraps the expression in `ko.pureComputed(...)` when needed) public static readonly ObservableTransformationAnnotation EnsureWrapped = new ObservableTransformationAnnotation(JsAstHelpers.EnsureObservableWrapped); } } diff --git a/src/Framework/Framework/Hosting/DotvvmPresenter.cs b/src/Framework/Framework/Hosting/DotvvmPresenter.cs index db046d877..dee997e54 100644 --- a/src/Framework/Framework/Hosting/DotvvmPresenter.cs +++ b/src/Framework/Framework/Hosting/DotvvmPresenter.cs @@ -538,8 +538,7 @@ Cross site iframe are disabled in this application. await context.RejectRequest($""" Pages can not be loaded using Javascript for security reasons. Try refreshing the page to get rid of the error. - If you are the developer, you can disable this check by setting DotvvmConfiguration.Security.VerifySecFetchForPages.ExcludeRoute("{route}"). [dest: {dest}, site: {site}]. - Note that this security check is not compatible with JavaScript-based prefetching, such as TurboLinks, Cloudflare Speed Brain, or similar, and you'll need to disable one of them. The check is "only" a deference-in-depth measure against XSS, and disabling it is not a vulnerability by itself. + If you are the developer, you can disable this check by setting DotvvmConfiguration.Security.VerifySecFetchForPages.ExcludeRoute("{route}"). [dest: {dest}, site: {site}] """); if (site != "same-origin") await context.RejectRequest($"Cross site SPA requests are disabled.");